Web Inspector: Should be a way to go directly from an event in the overview view...
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Oct 2018 19:09:29 +0000 (19:09 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Oct 2018 19:09:29 +0000 (19:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=135307
<rdar://problem/17273966>

Reviewed by Joseph Pecoraro.

When a `WI.TimelineRecordBar` is clicked, call up the delegate chain to the overview and
adjust the currently selected `WI.TimelineRecordBar` among the `WI.TimelineOverviewGraph`s.
Similarly, selecting a `WI.DataGridNode` in any `WI.TimelineView` subclass will use the same
logic to select the corresponding `WI.TimelineRecordBar`.

* UserInterface/Views/TimelineOverview.js:
(WI.TimelineOverview):
(WI.TimelineOverview.prototype.reset):
(WI.TimelineOverview.prototype._recordSelected):

* UserInterface/Views/TimelineOverviewGraph.js:
(WI.TimelineOverviewGraph):
(WI.TimelineOverviewGraph.prototype.set selectedRecord):
(WI.TimelineOverviewGraph.prototype.get selectedRecordBar): Added.
(WI.TimelineOverviewGraph.prototype.set selectedRecordBar): Added.
(WI.TimelineOverviewGraph.prototype.timelineRecordBarClicked): Added.
(WI.TimelineOverviewGraph.prototype._needsSelectedRecordLayout):

* UserInterface/Views/TimelineRecordBar.js:
(WI.TimelineRecordBar):
(WI.TimelineRecordBar.prototype.get selected): Added.
(WI.TimelineRecordBar.prototype.set selected): Added.
(WI.TimelineRecordBar.prototype._handleClick): Added.
* UserInterface/Views/TimelineRecordBar.css:
(.timeline-record-bar.selected > .segment): Added.
Add a `delegate` that is notified whenever the element is clicked.

* UserInterface/Views/TimelineDataGridNode.js:
(WI.TimelineDataGridNode.prototype.refreshGraph.createBar):
* UserInterface/Views/LayoutTimelineOverviewGraph.js:
(WI.LayoutTimelineOverviewGraph.prototype.updateSelectedRecord):
(WI.LayoutTimelineOverviewGraph.prototype._updateRowLayout.createBar):
* UserInterface/Views/NetworkTimelineOverviewGraph.js:
(WI.NetworkTimelineOverviewGraph.prototype.layout.createBar):
* UserInterface/Views/ScriptTimelineOverviewGraph.js:
(WI.ScriptTimelineOverviewGraph.prototype.layout.createBar):
(WI.ScriptTimelineOverviewGraph.prototype.updateSelectedRecord):

* UserInterface/Views/TimelineRecordingContentView.js:
(WI.TimelineRecordingContentView.prototype.showTimelineViewForTimeline):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237195 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Views/LayoutTimelineOverviewGraph.js
Source/WebInspectorUI/UserInterface/Views/NetworkTimelineOverviewGraph.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineOverviewGraph.js
Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/TimelineOverview.js
Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.css
Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js

index 0881b6b..a620064 100644 (file)
@@ -1,5 +1,54 @@
 2018-10-16  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Should be a way to go directly from an event in the overview view to the specialized timeline for that event
+        https://bugs.webkit.org/show_bug.cgi?id=135307
+        <rdar://problem/17273966>
+
+        Reviewed by Joseph Pecoraro.
+
+        When a `WI.TimelineRecordBar` is clicked, call up the delegate chain to the overview and
+        adjust the currently selected `WI.TimelineRecordBar` among the `WI.TimelineOverviewGraph`s.
+        Similarly, selecting a `WI.DataGridNode` in any `WI.TimelineView` subclass will use the same
+        logic to select the corresponding `WI.TimelineRecordBar`.
+
+        * UserInterface/Views/TimelineOverview.js:
+        (WI.TimelineOverview):
+        (WI.TimelineOverview.prototype.reset):
+        (WI.TimelineOverview.prototype._recordSelected):
+
+        * UserInterface/Views/TimelineOverviewGraph.js:
+        (WI.TimelineOverviewGraph):
+        (WI.TimelineOverviewGraph.prototype.set selectedRecord):
+        (WI.TimelineOverviewGraph.prototype.get selectedRecordBar): Added.
+        (WI.TimelineOverviewGraph.prototype.set selectedRecordBar): Added.
+        (WI.TimelineOverviewGraph.prototype.timelineRecordBarClicked): Added.
+        (WI.TimelineOverviewGraph.prototype._needsSelectedRecordLayout):
+
+        * UserInterface/Views/TimelineRecordBar.js:
+        (WI.TimelineRecordBar):
+        (WI.TimelineRecordBar.prototype.get selected): Added.
+        (WI.TimelineRecordBar.prototype.set selected): Added.
+        (WI.TimelineRecordBar.prototype._handleClick): Added.
+        * UserInterface/Views/TimelineRecordBar.css:
+        (.timeline-record-bar.selected > .segment): Added.
+        Add a `delegate` that is notified whenever the element is clicked.
+
+        * UserInterface/Views/TimelineDataGridNode.js:
+        (WI.TimelineDataGridNode.prototype.refreshGraph.createBar):
+        * UserInterface/Views/LayoutTimelineOverviewGraph.js:
+        (WI.LayoutTimelineOverviewGraph.prototype.updateSelectedRecord):
+        (WI.LayoutTimelineOverviewGraph.prototype._updateRowLayout.createBar):
+        * UserInterface/Views/NetworkTimelineOverviewGraph.js:
+        (WI.NetworkTimelineOverviewGraph.prototype.layout.createBar):
+        * UserInterface/Views/ScriptTimelineOverviewGraph.js:
+        (WI.ScriptTimelineOverviewGraph.prototype.layout.createBar):
+        (WI.ScriptTimelineOverviewGraph.prototype.updateSelectedRecord):
+
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        (WI.TimelineRecordingContentView.prototype.showTimelineViewForTimeline):
+
+2018-10-16  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: sequences of spaces longer than 16 don't show a dot
         https://bugs.webkit.org/show_bug.cgi?id=190528
 
index 6e54acb..e98030a 100644 (file)
@@ -68,6 +68,22 @@ WI.LayoutTimelineOverviewGraph = class LayoutTimelineOverviewGraph extends WI.Ti
         this._updateRowLayout(this._timelineLayoutRecordRow);
     }
 
+    updateSelectedRecord()
+    {
+        super.updateSelectedRecord();
+
+        for (let recordRow of [this._timelineLayoutRecordRow, this._timelinePaintRecordRow]) {
+            for (let recordBar of recordRow.recordBars) {
+                if (recordBar.records.includes(this.selectedRecord)) {
+                    this.selectedRecordBar = recordBar;
+                    return;
+                }
+            }
+        }
+
+        this.selectedRecordBar = null;
+    }
+
     // Private
 
     _updateRowLayout(row)
@@ -79,7 +95,7 @@ WI.LayoutTimelineOverviewGraph = class LayoutTimelineOverviewGraph extends WI.Ti
         {
             var timelineRecordBar = row.recordBars[recordBarIndex];
             if (!timelineRecordBar)
-                timelineRecordBar = row.recordBars[recordBarIndex] = new WI.TimelineRecordBar(records, renderMode);
+                timelineRecordBar = row.recordBars[recordBarIndex] = new WI.TimelineRecordBar(this, records, renderMode);
             else {
                 timelineRecordBar.renderMode = renderMode;
                 timelineRecordBar.records = records;
index bea7b64..74d94ab 100644 (file)
@@ -75,7 +75,7 @@ WI.NetworkTimelineOverviewGraph = class NetworkTimelineOverviewGraph extends WI.
         {
             let timelineRecordBar = rowRecordBars[recordBarIndex];
             if (!timelineRecordBar)
-                timelineRecordBar = rowRecordBars[recordBarIndex] = new WI.TimelineRecordBar(records, renderMode);
+                timelineRecordBar = rowRecordBars[recordBarIndex] = new WI.TimelineRecordBar(this, records, renderMode);
             else {
                 timelineRecordBar.renderMode = renderMode;
                 timelineRecordBar.records = records;
index 7d3b578..8e38ebf 100644 (file)
@@ -62,7 +62,7 @@ WI.ScriptTimelineOverviewGraph = class ScriptTimelineOverviewGraph extends WI.Ti
         {
             let timelineRecordBar = this._timelineRecordBars[recordBarIndex];
             if (!timelineRecordBar)
-                timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WI.TimelineRecordBar(records, renderMode);
+                timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WI.TimelineRecordBar(this, records, renderMode);
             else {
                 timelineRecordBar.renderMode = renderMode;
                 timelineRecordBar.records = records;
@@ -86,6 +86,20 @@ WI.ScriptTimelineOverviewGraph = class ScriptTimelineOverviewGraph extends WI.Ti
         }
     }
 
+    updateSelectedRecord()
+    {
+        super.updateSelectedRecord();
+
+        for (let recordBar of this._timelineRecordBars) {
+            if (recordBar.records.includes(this.selectedRecord)) {
+                this.selectedRecordBar = recordBar;
+                return;
+            }
+        }
+
+        this.selectedRecordBar = null;
+    }
+
     // Private
 
     _scriptTimelineRecordAdded(event)
index d6540a5..a2f6247 100644 (file)
@@ -241,7 +241,7 @@ WI.TimelineDataGridNode = class TimelineDataGridNode extends WI.DataGridNode
         {
             var timelineRecordBar = this._timelineRecordBars[recordBarIndex];
             if (!timelineRecordBar)
-                timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WI.TimelineRecordBar(records, renderMode);
+                timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WI.TimelineRecordBar(this, records, renderMode);
             else {
                 timelineRecordBar.renderMode = renderMode;
                 timelineRecordBar.records = records;
index f4ac2bd..5578b18 100644 (file)
@@ -55,6 +55,7 @@ WI.TimelineOverview = class TimelineOverview extends WI.View
         this._graphsContainerView.element.classList.add("graphs-container");
         this.addSubview(this._graphsContainerView);
 
+        this._selectedTimelineRecord = null;
         this._overviewGraphsByTypeMap = new Map;
 
         this._editInstrumentsButton = new WI.ActivateButtonNavigationItem("toggle-edit-instruments", WI.UIString("Edit configuration"), WI.UIString("Save configuration"));
@@ -371,6 +372,7 @@ WI.TimelineOverview = class TimelineOverview extends WI.View
 
     reset()
     {
+        this._selectedTimelineRecord = null;
         for (let overviewGraph of this._overviewGraphsByTypeMap.values())
             overviewGraph.reset();
 
@@ -707,13 +709,41 @@ WI.TimelineOverview = class TimelineOverview extends WI.View
 
     _recordSelected(event)
     {
+        let {record, recordBar} = event.data;
+        if (!record || record === this._selectedTimelineRecord)
+            return;
+
+        if (this._selectedTimelineRecord && this._selectedTimelineRecord.type !== record.type) {
+            let timelineOverviewGraph = this._overviewGraphsByTypeMap.get(this._selectedTimelineRecord.type);
+            console.assert(timelineOverviewGraph);
+            if (timelineOverviewGraph)
+                timelineOverviewGraph.selectedRecord = null;
+        }
+
+        this._selectedTimelineRecord = record;
+
+        if (this._selectedTimelineRecord) {
+            let firstRecord = this._selectedTimelineRecord;
+            let lastRecord = this._selectedTimelineRecord;
+            if (recordBar) {
+                firstRecord = recordBar.records[0];
+                lastRecord = recordBar.records.lastValue;
+            }
+
+            if (firstRecord.startTime < this.selectionStartTime || lastRecord.endTime > this.selectionStartTime + this.selectionDuration) {
+                let selectionPadding = this.secondsPerPixel * 10;
+                this.selectionStartTime = firstRecord.startTime - selectionPadding;
+                this.selectionDuration = lastRecord.endTime - firstRecord.startTime + (selectionPadding * 2);
+            }
+        }
+
         for (let [type, overviewGraph] of this._overviewGraphsByTypeMap) {
             if (overviewGraph !== event.target)
                 continue;
 
             let timeline = this._recording.timelines.get(type);
             console.assert(timeline, "Timeline recording missing timeline type", type);
-            this.dispatchEventToListeners(WI.TimelineOverview.Event.RecordSelected, {timeline, record: event.data.record});
+            this.dispatchEventToListeners(WI.TimelineOverview.Event.RecordSelected, {timeline, record: this._selectedTimelineRecord});
             return;
         }
     }
index 3afbc4d..88c5dfd 100644 (file)
@@ -37,7 +37,7 @@ WI.TimelineOverviewGraph = class TimelineOverviewGraph extends WI.View
         this._currentTime = 0;
         this._timelineOverview = timelineOverview;
         this._selectedRecord = null;
-        this._selectedRecordChanged = false;
+        this._selectedRecordBar = null;
         this._scheduledSelectedRecordLayoutUpdateIdentifier = undefined;
         this._selected = false;
         this._visible = true;
@@ -166,11 +166,32 @@ WI.TimelineOverviewGraph = class TimelineOverviewGraph extends WI.View
             return;
 
         this._selectedRecord = x;
-        this._selectedRecordChanged = true;
 
         this._needsSelectedRecordLayout();
     }
 
+    get selectedRecordBar()
+    {
+        return this._selectedRecordBar;
+    }
+
+    set selectedRecordBar(recordBar)
+    {
+        if (this._selectedRecordBar === recordBar)
+            return;
+
+        if (this._selectedRecordBar)
+            this._selectedRecordBar.selected = false;
+
+        this._selectedRecordBar = recordBar;
+
+        if (this._selectedRecordBar) {
+            this._selectedRecordBar.selected = true;
+
+            console.assert(this._selectedRecordBar.records.includes(this._selectedRecord));
+        }
+    }
+
     get height()
     {
         // Overridden by sub-classes if needed.
@@ -226,6 +247,13 @@ WI.TimelineOverviewGraph = class TimelineOverviewGraph extends WI.View
         super.needsLayout();
     }
 
+    // TimelineRecordBar delegate
+
+    timelineRecordBarClicked(timelineRecordBar)
+    {
+        this.selectedRecord = timelineRecordBar.records[0];
+    }
+
     // Protected
 
     updateSelectedRecord()
@@ -248,7 +276,7 @@ WI.TimelineOverviewGraph = class TimelineOverviewGraph extends WI.View
             this._scheduledSelectedRecordLayoutUpdateIdentifier = undefined;
 
             this.updateSelectedRecord();
-            this.dispatchEventToListeners(WI.TimelineOverviewGraph.Event.RecordSelected, {record: this.selectedRecord});
+            this.dispatchEventToListeners(WI.TimelineOverviewGraph.Event.RecordSelected, {record: this.selectedRecord, recordBar: this.selectedRecordBar});
         });
     }
 };
index c2a5381..4557799 100644 (file)
     z-index: 1;
 }
 
+.timeline-record-bar.selected > .segment {
+    background-color: var(--selected-background-color) !important;
+    border-color: var(--selected-background-color-active) !important;
+}
+
 .timeline-record-bar:not(.has-inactive-segment) > .segment {
     left: 0;
     width: 100%;
index 358f71f..f1885af 100644 (file)
 
 WI.TimelineRecordBar = class TimelineRecordBar extends WI.Object
 {
-    constructor(records, renderMode)
+    constructor(delegate, records, renderMode)
     {
         super();
 
+        this._delegate = delegate;
+
         this._element = document.createElement("div");
         this._element.classList.add("timeline-record-bar");
         this._element[WI.TimelineRecordBar.ElementReferenceSymbol] = this;
+        this._element.addEventListener("click", this._handleClick.bind(this));
 
         this.renderMode = renderMode;
         this.records = records;
@@ -179,6 +182,16 @@ WI.TimelineRecordBar = class TimelineRecordBar extends WI.Object
         return this._element;
     }
 
+    get selected()
+    {
+        return this._element.classList.contains("selected");
+    }
+
+    set selected(selected)
+    {
+        this._element.classList.toggle("selected", !!selected);
+    }
+
     get renderMode()
     {
         return this._renderMode;
@@ -372,6 +385,12 @@ WI.TimelineRecordBar = class TimelineRecordBar extends WI.Object
         if (currentPositionAprox !== newPositionAprox)
             element.style[property] = (newPositionAprox / 100) + "%";
     }
+
+    _handleClick(event)
+    {
+        if (this._delegate.timelineRecordBarClicked)
+            this._delegate.timelineRecordBarClicked(this);
+    }
 };
 
 WI.TimelineRecordBar.ElementReferenceSymbol = Symbol("timeline-record-bar");
index deabdfb..f54c767 100644 (file)
@@ -114,7 +114,13 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
         if (!this._timelineViewMap.has(timeline))
             return;
 
-        this._timelineContentBrowser.showContentView(this._timelineViewMap.get(timeline));
+        let contentView = this._timelineContentBrowser.showContentView(this._timelineViewMap.get(timeline));
+
+        // FIXME: `WI.HeapAllocationsTimelineView` relies on it's `_dataGrid` for determining what
+        // object is currently selected. If that `_dataGrid` hasn't yet called `layout()` when first
+        // shown, we will lose the selection.
+        if (!contentView.didInitialLayout)
+            contentView.updateLayout();
     }
 
     get supportsSplitContentBrowser()