Title: [200067] trunk/Source/WebInspectorUI
Revision
200067
Author
[email protected]
Date
2016-04-25 18:00:17 -0700 (Mon, 25 Apr 2016)

Log Message

Web Inspector: hook up grid row filtering in the new Timelines UI
https://bugs.webkit.org/show_bug.cgi?id=154924
<rdar://problem/24934607>

Reviewed by Timothy Hatcher.

Re-implement timeline data grid filtering that previously existed in the
navigation sidebar. This patch adds support for filter text, scope bars,
and filtering based on ruler selection.

Multi-column filter support is now part of DataGrid. The grid checks compares
filter text against cell data of type string. DataGridNode subclasses may
provide custom string data for columns that format complex objects (such
as SourceCodeLocations). Cells containing data of type number are not
considered for filtering at this time.

* UserInterface/Views/DataGrid.js:
(WebInspector.DataGrid):
(WebInspector.DataGrid.prototype.set filterText):
(WebInspector.DataGrid.prototype.get filterDelegate):
(WebInspector.DataGrid.prototype.set filterDelegate):
(WebInspector.DataGrid.prototype.filterDidChange):
Called internally by the grid whenever the filter text or delegate changes.
Also called by clients that implement a filter delegate, to inform the
grid that a custom filter has changed.

(WebInspector.DataGrid.prototype.hasCustomFilters):
(WebInspector.DataGrid.prototype.matchNodeAgainstCustomFilters):
Calls the filter delegate, if it exists, and provides a hook for
subclasses to provide custom filtering.

(WebInspector.DataGrid.prototype._applyFiltersToNode.matchTextFilter):
(WebInspector.DataGrid.prototype._applyFiltersToNode.makeVisible):
(WebInspector.DataGrid.prototype._applyFiltersToNode):
Filters data grid nodes and fires filter events as needed.
(WebInspector.DataGrid.prototype._hasFilterDelegate):
Helper function.
(WebInspector.DataGrid.prototype._updateVisibleRows):
Exclude hidden nodes from revealed rows.
(WebInspector.DataGrid.prototype._updateFilter):
Filtering entry point, called on an animation frame. Updates visible
rows if any node was filtered/unfiltered.

(WebInspector.DataGridNode):
(WebInspector.DataGridNode.prototype.get filterableData):
Gets an array of filterable strings for the node.
(WebInspector.DataGridNode.prototype.refresh):
Resets cached filterable strings.
(WebInspector.DataGridNode.prototype.filterableDataForColumn):
Can be overridden by subclasses to provide filterable text for complex
cell data, like as objects formatted as document fragments.

* UserInterface/Views/LayoutTimelineDataGridNode.js:
(WebInspector.LayoutTimelineDataGridNode.prototype.get data):

* UserInterface/Views/LayoutTimelineView.js:
(WebInspector.LayoutTimelineView):
Register grid and remove logic that has been moved to the base class.
(WebInspector.LayoutTimelineView.prototype.filterDidChange):
Update highlight after grid filter change.
(WebInspector.LayoutTimelineView.prototype._dataGridSelectedNodeChanged):
Update highlight when selection changes.
(WebInspector.LayoutTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
(WebInspector.LayoutTimelineView.prototype.treeElementDeselected): Deleted.
(WebInspector.LayoutTimelineView.prototype._dataGridFiltersDidChange): Deleted.
(WebInspector.LayoutTimelineView.prototype._dataGridNodeSelected): Deleted.
No longer needed.

* UserInterface/Views/NetworkTimelineView.js:
(WebInspector.NetworkTimelineView):
Register grid and remove logic that has been moved to the base class.
(WebInspector.NetworkTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
(WebInspector.NetworkTimelineView.prototype._dataGridFiltersDidChange): Deleted.
(WebInspector.NetworkTimelineView.prototype._dataGridNodeSelected): Deleted.
No longer needed.

* UserInterface/Views/OverviewTimelineView.js:
(WebInspector.OverviewTimelineView):
Register grid and remove logic that has been moved to the base class.
(WebInspector.OverviewTimelineView.prototype._dataGridNodeSelected): Deleted.
No longer needed.

* UserInterface/Views/RenderingFrameTimelineView.js:
(WebInspector.RenderingFrameTimelineView):
Register grid and remove logic that has been moved to the base class.
(WebInspector.RenderingFrameTimelineView.prototype.get filterStartTime):
(WebInspector.RenderingFrameTimelineView.prototype.get filterEndTime):
Convert selection indices into filter start and end times.
(WebInspector.RenderingFrameTimelineView.prototype.matchDataGridNodeAgainstCustomFilters):
Perform custom filtering on rendering frame duration.
(WebInspector.RenderingFrameTimelineView.prototype._scopeBarSelectionDidChange):
Inform grid of custom filter change.
(WebInspector.RenderingFrameTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
(WebInspector.RenderingFrameTimelineView.prototype._dataGridNodeSelected): Deleted.
No longer needed.

* UserInterface/Views/ResourceTimelineDataGridNode.js:
(WebInspector.ResourceTimelineDataGridNode.prototype.filterableDataForColumn):
Use URL string for filtering "name" column.

* UserInterface/Views/ScriptClusterTimelineView.js:
(WebInspector.ScriptClusterTimelineView.prototype.updateFilter):
Forwarding for TimelineView API.
(WebInspector.ScriptClusterTimelineView.prototype.matchDataGridNodeAgainstCustomFilters):
(WebInspector.ScriptClusterTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
Renamed to matchDataGridNodeAgainstCustomFilters.
(WebInspector.ScriptClusterTimelineView.prototype._scriptClusterViewCurrentContentViewDidChange): Deleted.
Removed FIXME comment. Updating TimelineView times is sufficient to trigger filtering.

* UserInterface/Views/ScriptDetailsTimelineView.js:
(WebInspector.ScriptDetailsTimelineView):
Register grid and remove logic that has been moved to the base class.
(WebInspector.ScriptDetailsTimelineView.prototype._dataGridFiltersDidChange): Deleted.
(WebInspector.ScriptDetailsTimelineView.prototype._dataGridNodeSelected): Deleted.
No longer needed.

* UserInterface/Views/ScriptTimelineDataGridNode.js:
(WebInspector.ScriptTimelineDataGridNode.prototype.filterableDataForColumn):
Use main title and subtitle strings for filtering "name" column.
(WebInspector.ScriptTimelineDataGridNode.prototype._createNameCellDocumentFragment):
(WebInspector.ScriptTimelineDataGridNode.prototype._subtitle):
Break out for use in filterableDataForColumn.

* UserInterface/Views/TimelineDataGrid.js:
(WebInspector.TimelineDataGrid):
Cleanup variable names.
(WebInspector.TimelineDataGrid.prototype.hasCustomFilters):
Always true because filtering on ruler selection always occurs.
(WebInspector.TimelineDataGrid.prototype.matchNodeAgainstCustomFilters):
Match nodes against scope bar filters.
(WebInspector.TimelineDataGrid.prototype._scopeBarSelectedItemsDidChange):
Inform grid of custom filter change.
(WebInspector.TimelineDataGrid.prototype.treeElementMatchesActiveScopeFilters): Deleted.
Re-implemented as _nodeMatchesActiveScopeFilters.
(WebInspector.TimelineDataGrid.prototype._updateScopeBarForcedVisibility): Deleted.
Old UI. No longer needed.

* UserInterface/Views/TimelineDataGridNode.js:
(WebInspector.TimelineDataGridNode.prototype.filterableDataForColumn):
Filter strings for SourceCodeLocation and CallFrame objects.

* UserInterface/Views/TimelineRecordingContentView.js:
(WebInspector.TimelineRecordingContentView):
Listen for FilterBar changes and TimelineView record filtering.
(WebInspector.TimelineRecordingContentView.prototype._filterDidChange):
Update grid filters when filter bar changes.
(WebInspector.TimelineRecordingContentView.prototype._recordWasFiltered):
Update overview when records are filtered/unfiltered.
(WebInspector.TimelineRecordingContentView.prototype.filterDidChange): Deleted.
(WebInspector.TimelineRecordingContentView.prototype.recordWasFiltered): Deleted.
(WebInspector.TimelineRecordingContentView.prototype.matchTreeElementAgainstCustomFilters.checkTimeBounds): Deleted.
(WebInspector.TimelineRecordingContentView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
Re-implemented in DataGrid.
(WebInspector.TimelineRecordingContentView.prototype._updateTimes): Deleted.
FIXME comment removed. Filtering occurs when TimelineView times are updated.
(WebInspector.TimelineRecordingContentView.prototype._timeRangeSelectionChanged): Deleted.

* UserInterface/Views/TimelineView.js:
(WebInspector.TimelineView):
(WebInspector.TimelineView.prototype.get navigationItems):
Used by TimelineRecordingContentView to add scope bar items to the
lower content browser's navigation bar.

(WebInspector.TimelineView.prototype.set startTime):
(WebInspector.TimelineView.prototype.set endTime):
(WebInspector.TimelineView.prototype.set currentTime):
Update grid filter when recording times change.
(WebInspector.TimelineView.prototype.get filterStartTime):
(WebInspector.TimelineView.prototype.get filterEndTime):
Let subclasses (RenderingFrameTimelineView) provide filter start/end times.
(WebInspector.TimelineView.prototype.setupDataGrid):
Register the grid used by the TimelineView subclass, allowing the base
class to hook into common event listeners and provide boilerplate functionality.

(WebInspector.TimelineView.prototype.updateFilter):
For data grid views, updates grid filters and sets new filter text.
(WebInspector.TimelineView.prototype.matchDataGridNodeAgainstCustomFilters):
(WebInspector.TimelineView.prototype.dataGridMatchNodeAgainstCustomFilters.checkTimeBounds):
(WebInspector.TimelineView.prototype.dataGridMatchNodeAgainstCustomFilters):
DataGrid filter delegate. Lets subclasses apply custom filters first,
then filters based on ruler selection if needed.

(WebInspector.TimelineView.prototype.filterDidChange):
Hook for subclasses to respond to filter changes.
(WebInspector.TimelineView.prototype._filterTimesDidChange.delayedWork):
(WebInspector.TimelineView.prototype._filterTimesDidChange):
Helper function for coalescing ruler selection updates into a single
filter update.

(WebInspector.TimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
(WebInspector.TimelineView.prototype.filterUpdated): Deleted.
No longer needed.

Modified Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (200066 => 200067)


--- trunk/Source/WebInspectorUI/ChangeLog	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/ChangeLog	2016-04-26 01:00:17 UTC (rev 200067)
@@ -1,3 +1,198 @@
+2016-04-25  Matt Baker  <[email protected]>
+
+        Web Inspector: hook up grid row filtering in the new Timelines UI
+        https://bugs.webkit.org/show_bug.cgi?id=154924
+        <rdar://problem/24934607>
+
+        Reviewed by Timothy Hatcher.
+
+        Re-implement timeline data grid filtering that previously existed in the
+        navigation sidebar. This patch adds support for filter text, scope bars,
+        and filtering based on ruler selection.
+
+        Multi-column filter support is now part of DataGrid. The grid checks compares
+        filter text against cell data of type string. DataGridNode subclasses may
+        provide custom string data for columns that format complex objects (such
+        as SourceCodeLocations). Cells containing data of type number are not
+        considered for filtering at this time.
+
+        * UserInterface/Views/DataGrid.js:
+        (WebInspector.DataGrid):
+        (WebInspector.DataGrid.prototype.set filterText):
+        (WebInspector.DataGrid.prototype.get filterDelegate):
+        (WebInspector.DataGrid.prototype.set filterDelegate):
+        (WebInspector.DataGrid.prototype.filterDidChange):
+        Called internally by the grid whenever the filter text or delegate changes.
+        Also called by clients that implement a filter delegate, to inform the
+        grid that a custom filter has changed.
+
+        (WebInspector.DataGrid.prototype.hasCustomFilters):
+        (WebInspector.DataGrid.prototype.matchNodeAgainstCustomFilters):
+        Calls the filter delegate, if it exists, and provides a hook for
+        subclasses to provide custom filtering.
+
+        (WebInspector.DataGrid.prototype._applyFiltersToNode.matchTextFilter):
+        (WebInspector.DataGrid.prototype._applyFiltersToNode.makeVisible):
+        (WebInspector.DataGrid.prototype._applyFiltersToNode):
+        Filters data grid nodes and fires filter events as needed.
+        (WebInspector.DataGrid.prototype._hasFilterDelegate):
+        Helper function.
+        (WebInspector.DataGrid.prototype._updateVisibleRows):
+        Exclude hidden nodes from revealed rows.
+        (WebInspector.DataGrid.prototype._updateFilter):
+        Filtering entry point, called on an animation frame. Updates visible
+        rows if any node was filtered/unfiltered.
+
+        (WebInspector.DataGridNode):
+        (WebInspector.DataGridNode.prototype.get filterableData):
+        Gets an array of filterable strings for the node.
+        (WebInspector.DataGridNode.prototype.refresh):
+        Resets cached filterable strings.
+        (WebInspector.DataGridNode.prototype.filterableDataForColumn):
+        Can be overridden by subclasses to provide filterable text for complex
+        cell data, like as objects formatted as document fragments.
+
+        * UserInterface/Views/LayoutTimelineDataGridNode.js:
+        (WebInspector.LayoutTimelineDataGridNode.prototype.get data):
+
+        * UserInterface/Views/LayoutTimelineView.js:
+        (WebInspector.LayoutTimelineView):
+        Register grid and remove logic that has been moved to the base class.
+        (WebInspector.LayoutTimelineView.prototype.filterDidChange):
+        Update highlight after grid filter change.
+        (WebInspector.LayoutTimelineView.prototype._dataGridSelectedNodeChanged):
+        Update highlight when selection changes.
+        (WebInspector.LayoutTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
+        (WebInspector.LayoutTimelineView.prototype.treeElementDeselected): Deleted.
+        (WebInspector.LayoutTimelineView.prototype._dataGridFiltersDidChange): Deleted.
+        (WebInspector.LayoutTimelineView.prototype._dataGridNodeSelected): Deleted.
+        No longer needed.
+
+        * UserInterface/Views/NetworkTimelineView.js:
+        (WebInspector.NetworkTimelineView):
+        Register grid and remove logic that has been moved to the base class.
+        (WebInspector.NetworkTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
+        (WebInspector.NetworkTimelineView.prototype._dataGridFiltersDidChange): Deleted.
+        (WebInspector.NetworkTimelineView.prototype._dataGridNodeSelected): Deleted.
+        No longer needed.
+
+        * UserInterface/Views/OverviewTimelineView.js:
+        (WebInspector.OverviewTimelineView):
+        Register grid and remove logic that has been moved to the base class.
+        (WebInspector.OverviewTimelineView.prototype._dataGridNodeSelected): Deleted.
+        No longer needed.
+
+        * UserInterface/Views/RenderingFrameTimelineView.js:
+        (WebInspector.RenderingFrameTimelineView):
+        Register grid and remove logic that has been moved to the base class.
+        (WebInspector.RenderingFrameTimelineView.prototype.get filterStartTime):
+        (WebInspector.RenderingFrameTimelineView.prototype.get filterEndTime):
+        Convert selection indices into filter start and end times.
+        (WebInspector.RenderingFrameTimelineView.prototype.matchDataGridNodeAgainstCustomFilters):
+        Perform custom filtering on rendering frame duration.
+        (WebInspector.RenderingFrameTimelineView.prototype._scopeBarSelectionDidChange):
+        Inform grid of custom filter change.
+        (WebInspector.RenderingFrameTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
+        (WebInspector.RenderingFrameTimelineView.prototype._dataGridNodeSelected): Deleted.
+        No longer needed.
+
+        * UserInterface/Views/ResourceTimelineDataGridNode.js:
+        (WebInspector.ResourceTimelineDataGridNode.prototype.filterableDataForColumn):
+        Use URL string for filtering "name" column.
+
+        * UserInterface/Views/ScriptClusterTimelineView.js:
+        (WebInspector.ScriptClusterTimelineView.prototype.updateFilter):
+        Forwarding for TimelineView API.
+        (WebInspector.ScriptClusterTimelineView.prototype.matchDataGridNodeAgainstCustomFilters):
+        (WebInspector.ScriptClusterTimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
+        Renamed to matchDataGridNodeAgainstCustomFilters.
+        (WebInspector.ScriptClusterTimelineView.prototype._scriptClusterViewCurrentContentViewDidChange): Deleted.
+        Removed FIXME comment. Updating TimelineView times is sufficient to trigger filtering.
+
+        * UserInterface/Views/ScriptDetailsTimelineView.js:
+        (WebInspector.ScriptDetailsTimelineView):
+        Register grid and remove logic that has been moved to the base class.
+        (WebInspector.ScriptDetailsTimelineView.prototype._dataGridFiltersDidChange): Deleted.
+        (WebInspector.ScriptDetailsTimelineView.prototype._dataGridNodeSelected): Deleted.
+        No longer needed.
+
+        * UserInterface/Views/ScriptTimelineDataGridNode.js:
+        (WebInspector.ScriptTimelineDataGridNode.prototype.filterableDataForColumn):
+        Use main title and subtitle strings for filtering "name" column.
+        (WebInspector.ScriptTimelineDataGridNode.prototype._createNameCellDocumentFragment):
+        (WebInspector.ScriptTimelineDataGridNode.prototype._subtitle):
+        Break out for use in filterableDataForColumn.
+
+        * UserInterface/Views/TimelineDataGrid.js:
+        (WebInspector.TimelineDataGrid):
+        Cleanup variable names.
+        (WebInspector.TimelineDataGrid.prototype.hasCustomFilters):
+        Always true because filtering on ruler selection always occurs.
+        (WebInspector.TimelineDataGrid.prototype.matchNodeAgainstCustomFilters):
+        Match nodes against scope bar filters.
+        (WebInspector.TimelineDataGrid.prototype._scopeBarSelectedItemsDidChange):
+        Inform grid of custom filter change.
+        (WebInspector.TimelineDataGrid.prototype.treeElementMatchesActiveScopeFilters): Deleted.
+        Re-implemented as _nodeMatchesActiveScopeFilters.
+        (WebInspector.TimelineDataGrid.prototype._updateScopeBarForcedVisibility): Deleted.
+        Old UI. No longer needed.
+
+        * UserInterface/Views/TimelineDataGridNode.js:
+        (WebInspector.TimelineDataGridNode.prototype.filterableDataForColumn):
+        Filter strings for SourceCodeLocation and CallFrame objects.
+
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        (WebInspector.TimelineRecordingContentView):
+        Listen for FilterBar changes and TimelineView record filtering.
+        (WebInspector.TimelineRecordingContentView.prototype._filterDidChange):
+        Update grid filters when filter bar changes.
+        (WebInspector.TimelineRecordingContentView.prototype._recordWasFiltered):
+        Update overview when records are filtered/unfiltered.
+        (WebInspector.TimelineRecordingContentView.prototype.filterDidChange): Deleted.
+        (WebInspector.TimelineRecordingContentView.prototype.recordWasFiltered): Deleted.
+        (WebInspector.TimelineRecordingContentView.prototype.matchTreeElementAgainstCustomFilters.checkTimeBounds): Deleted.
+        (WebInspector.TimelineRecordingContentView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
+        Re-implemented in DataGrid.
+        (WebInspector.TimelineRecordingContentView.prototype._updateTimes): Deleted.
+        FIXME comment removed. Filtering occurs when TimelineView times are updated.
+        (WebInspector.TimelineRecordingContentView.prototype._timeRangeSelectionChanged): Deleted.
+
+        * UserInterface/Views/TimelineView.js:
+        (WebInspector.TimelineView):
+        (WebInspector.TimelineView.prototype.get navigationItems):
+        Used by TimelineRecordingContentView to add scope bar items to the
+        lower content browser's navigation bar.
+
+        (WebInspector.TimelineView.prototype.set startTime):
+        (WebInspector.TimelineView.prototype.set endTime):
+        (WebInspector.TimelineView.prototype.set currentTime):
+        Update grid filter when recording times change.
+        (WebInspector.TimelineView.prototype.get filterStartTime):
+        (WebInspector.TimelineView.prototype.get filterEndTime):
+        Let subclasses (RenderingFrameTimelineView) provide filter start/end times.
+        (WebInspector.TimelineView.prototype.setupDataGrid):
+        Register the grid used by the TimelineView subclass, allowing the base
+        class to hook into common event listeners and provide boilerplate functionality.
+
+        (WebInspector.TimelineView.prototype.updateFilter):
+        For data grid views, updates grid filters and sets new filter text.
+        (WebInspector.TimelineView.prototype.matchDataGridNodeAgainstCustomFilters):
+        (WebInspector.TimelineView.prototype.dataGridMatchNodeAgainstCustomFilters.checkTimeBounds):
+        (WebInspector.TimelineView.prototype.dataGridMatchNodeAgainstCustomFilters):
+        DataGrid filter delegate. Lets subclasses apply custom filters first,
+        then filters based on ruler selection if needed.
+
+        (WebInspector.TimelineView.prototype.filterDidChange):
+        Hook for subclasses to respond to filter changes.
+        (WebInspector.TimelineView.prototype._filterTimesDidChange.delayedWork):
+        (WebInspector.TimelineView.prototype._filterTimesDidChange):
+        Helper function for coalescing ruler selection updates into a single
+        filter update.
+
+        (WebInspector.TimelineView.prototype.matchTreeElementAgainstCustomFilters): Deleted.
+        (WebInspector.TimelineView.prototype.filterUpdated): Deleted.
+        No longer needed.
+
 2016-04-25  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: React.js JSXTransformer produces bogus error locations

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -53,6 +53,9 @@
         this.resizers = [];
         this._columnWidthsInitialized = false;
 
+        this._filterText = "";
+        this._filterDelegate = null;
+
         this.element.className = "data-grid";
         this.element.tabIndex = 0;
         this.element.addEventListener("keydown", this._keyDown.bind(this), false);
@@ -281,6 +284,112 @@
             this._scrollContainerElement.addEventListener("scroll", this._scrollListener);
     }
 
+    set filterText(x)
+    {
+        if (this._filterText === x)
+            return;
+
+        this._filterText = x;
+        this.filterDidChange();
+    }
+
+    get filterDelegate() { return this._filterDelegate; }
+
+    set filterDelegate(delegate)
+    {
+        this._filterDelegate = delegate;
+        this.filterDidChange();
+    }
+
+    filterDidChange()
+    {
+        if (this._scheduledFilterUpdateIdentifier)
+            return;
+
+        this._scheduledFilterUpdateIdentifier = requestAnimationFrame(this._updateFilter.bind(this));
+    }
+
+    hasCustomFilters()
+    {
+        return this._hasFilterDelegate();
+    }
+
+    matchNodeAgainstCustomFilters(node)
+    {
+        if (!this._hasFilterDelegate())
+            return true;
+        return this._filterDelegate.dataGridMatchNodeAgainstCustomFilters(node);
+    }
+
+    _applyFiltersToNode(node)
+    {
+        if (!this._textFilterRegex && !this.hasCustomFilters()) {
+            // No filters, so make everything visible.
+            node.hidden = false;
+
+            // If the node was expanded during filtering, collapse it again.
+            if (node.expanded && node[WebInspector.DataGrid.WasExpandedDuringFilteringSymbol]) {
+                node[WebInspector.DataGrid.WasExpandedDuringFilteringSymbol] = false;
+                node.collapse();
+            }
+
+            return;
+        }
+
+        let filterableData = node.filterableData || [];
+        let flags = {expandNode: false};
+        let filterRegex = this._textFilterRegex;
+
+        function matchTextFilter()
+        {
+            if (!filterableData.length || !filterRegex)
+                return true;
+
+            if (filterableData.some((value) => filterRegex.test(value))) {
+                flags.expandNode = true;
+                return true;
+            }
+
+            return false;
+        }
+
+        function makeVisible()
+        {
+            // Make this element visible.
+            node.hidden = false;
+
+            // Make the ancestors visible and expand them.
+            let currentAncestor = node.parent;
+            while (currentAncestor && !currentAncestor.root) {
+                currentAncestor.hidden = false;
+
+                // Only expand if the built-in filters matched, not custom filters.
+                if (flags.expandNode && !currentAncestor.expanded) {
+                    currentAncestor[WebInspector.DataGrid.WasExpandedDuringFilteringSymbol] = true;
+                    currentAncestor.expand();
+                }
+
+                currentAncestor = currentAncestor.parent;
+            }
+        }
+
+        if (matchTextFilter() && this.matchNodeAgainstCustomFilters(node)) {
+            // Make the node visible since it matches.
+            makeVisible();
+
+            // If the node didn't match a built-in filter and was expanded earlier during filtering, collapse it again.
+            if (!flags.expandNode && node.expanded && node[WebInspector.DataGrid.WasExpandedDuringFilteringSymbol]) {
+                node[WebInspector.DataGrid.WasExpandedDuringFilteringSymbol] = false;
+                node.collapse();
+            }
+
+            return;
+        }
+
+        // Make the node invisible since it does not match.
+        node.hidden = true;
+    }
+
     _updateSortedColumn(oldSortColumnIdentifier)
     {
         if (this._sortColumnIdentifierSetting)
@@ -301,6 +410,11 @@
         this.dispatchEventToListeners(WebInspector.DataGrid.Event.SortChanged);
     }
 
+    _hasFilterDelegate()
+    {
+        return this._filterDelegate && typeof this._filterDelegate.dataGridMatchNodeAgainstCustomFilters === "function";
+    }
+
     _ondblclick(event)
     {
         if (this._editing || this._editingNode)
@@ -867,7 +981,7 @@
         let rowHeight = this.rowHeight;
         let updateOffsetThreshold = rowHeight * 5;
 
-        let revealedRows = this._rows.filter((row) => row.revealed);
+        let revealedRows = this._rows.filter((row) => row.revealed && !row.hidden);
 
         let scrollTop = this._scrollContainerElement.scrollTop;
         let scrollHeight = this._scrollContainerElement.offsetHeight;
@@ -1569,13 +1683,51 @@
 
         this._currentResizer = null;
     }
+
+    _updateFilter()
+    {
+        if (this._scheduledFilterUpdateIdentifier) {
+            cancelAnimationFrame(this._scheduledFilterUpdateIdentifier);
+            this._scheduledFilterUpdateIdentifier = undefined;
+        }
+
+        if (!this._rows.length)
+            return;
+
+        this._textFilterRegex = simpleGlobStringToRegExp(this._filterText, "i");
+
+        // Don't populate if we don't have any active filters.
+        // We only need to populate when a filter needs to reveal.
+        let dontPopulate = !this._textFilterRegex && !this.hasCustomFilters();
+
+        let filterDidModifyNode = false;
+        let currentNode = this._rows[0];
+        while (currentNode && !currentNode.root) {
+            const currentNodeWasHidden = currentNode.hidden;
+            this._applyFiltersToNode(currentNode);
+            if (currentNodeWasHidden !== currentNode.hidden) {
+                this.dispatchEventToListeners(WebInspector.DataGrid.Event.NodeWasFiltered, {node: currentNode});
+                filterDidModifyNode = true;
+            }
+
+            currentNode = currentNode.traverseNextNode(false, null, dontPopulate);
+        }
+
+        if (!filterDidModifyNode)
+            return;
+
+        this._updateVisibleRows();
+        this.dispatchEventToListeners(WebInspector.DataGrid.Event.FilterDidChange);
+    }
 };
 
 WebInspector.DataGrid.Event = {
     SortChanged: "datagrid-sort-changed",
     SelectedNodeChanged: "datagrid-selected-node-changed",
     ExpandedNode: "datagrid-expanded-node",
-    CollapsedNode: "datagrid-collapsed-node"
+    CollapsedNode: "datagrid-collapsed-node",
+    FilterDidChange: "datagrid-filter-did-change",
+    NodeWasFiltered: "datagrid-node-was-filtered"
 };
 
 WebInspector.DataGrid.ResizeMethod = {
@@ -1592,6 +1744,7 @@
 
 WebInspector.DataGrid.PreviousColumnOrdinalSymbol = Symbol("previous-column-ordinal");
 WebInspector.DataGrid.NextColumnOrdinalSymbol = Symbol("next-column-ordinal");
+WebInspector.DataGrid.WasExpandedDuringFilteringSymbol = Symbol("was-expanded-during-filtering");
 
 WebInspector.DataGrid.ColumnResizePadding = 10;
 WebInspector.DataGrid.CenterResizerOverBorderAdjustment = 3;
@@ -1726,6 +1879,30 @@
         this.needsRefresh();
     }
 
+    get filterableData()
+    {
+        if (this._cachedFilterableData)
+            return this._cachedFilterableData;
+
+        this._cachedFilterableData = [];
+
+        for (let column of this.dataGrid.columns.values()) {
+            let value = this.filterableDataForColumn(column.columnIdentifier);
+            if (!value)
+                continue;
+
+            if (!(value instanceof Array))
+                value = [value];
+
+            if (!value.length)
+                continue;
+
+            this._cachedFilterableData = this._cachedFilterableData.concat(value);
+        }
+
+        return this._cachedFilterableData;
+    }
+
     get revealed()
     {
         if ("_revealed" in this)
@@ -1856,6 +2033,7 @@
             this._scheduledRefreshIdentifier = undefined;
         }
 
+        this._cachedFilterableData = null;
         this._needsRefresh = false;
 
         this._element.removeChildren();
@@ -2254,6 +2432,14 @@
         // Subclasses may override
         return null;
     }
+
+    // Protected
+
+    filterableDataForColumn(columnIdentifier)
+    {
+        let value = this.data[columnIdentifier];
+        return typeof value === "string" ? value : null;
+    }
 };
 
 // Used to create a new table row when entering new data by editing cells.

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineDataGridNode.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineDataGridNode.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineDataGridNode.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -44,6 +44,7 @@
     {
         if (!this._cachedData) {
             this._cachedData = {
+                type: this._record.eventType,
                 name: this.displayName(),
                 width: this._record.width,
                 height: this._record.height,

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -31,7 +31,7 @@
 
         console.assert(timeline.type === WebInspector.TimelineRecord.Type.Layout, timeline);
 
-        let columns = {name: {}, location: {}, width: {}, height: {}, startTime: {}, totalTime: {}};
+        let columns = {type: {}, name: {}, location: {}, width: {}, height: {}, startTime: {}, totalTime: {}};
 
         columns.name.title = WebInspector.UIString("Type");
         columns.name.width = "15%";
@@ -42,11 +42,13 @@
             typeToLabelMap.set(value, WebInspector.LayoutTimelineRecord.displayNameForEventType(value));
         }
 
-        columns.name.scopeBar = WebInspector.TimelineDataGrid.createColumnScopeBar("layout", typeToLabelMap);
+        columns.type.scopeBar = WebInspector.TimelineDataGrid.createColumnScopeBar("layout", typeToLabelMap);
+        columns.type.hidden = true;
+
         columns.name.disclosure = true;
         columns.name.icon = true;
 
-        this._scopeBar = columns.name.scopeBar;
+        this._scopeBar = columns.type.scopeBar;
 
         columns.location.title = WebInspector.UIString("Initiator");
         columns.location.width = "25%";
@@ -69,9 +71,10 @@
             columns[column].sortable = true;
 
         this._dataGrid = new WebInspector.LayoutTimelineDataGrid(columns);
-        this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this);
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
+        this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridSelectedNodeChanged, this);
 
+        this.setupDataGrid(this._dataGrid);
+
         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("layout-timeline-view-sort", "startTime");
         this._dataGrid.sortOrderSetting = new WebInspector.Setting("layout-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
 
@@ -141,18 +144,6 @@
         this._dataGrid.closed();
     }
 
-    filterDidChange()
-    {
-        super.filterDidChange();
-
-        this._updateHighlight();
-    }
-
-    matchTreeElementAgainstCustomFilters(treeElement)
-    {
-        return this._dataGrid.treeElementMatchesActiveScopeFilters(treeElement);
-    }
-
     reset()
     {
         super.reset();
@@ -174,9 +165,9 @@
         dataGridNode.revealAndSelect();
     }
 
-    treeElementDeselected(treeElement)
+    filterDidChange()
     {
-        super.treeElementDeselected(treeElement);
+        super.filterDidChange();
 
         this._updateHighlight();
     }
@@ -246,16 +237,6 @@
         this.needsLayout();
     }
 
-    _dataGridFiltersDidChange(event)
-    {
-        // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
-    }
-
-    _dataGridNodeSelected(event)
-    {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
-    }
-
     _updateHighlight()
     {
         var record = this._hoveredOrSelectedRecord();
@@ -327,4 +308,9 @@
         this._hoveredDataGridNode = null;
         this._updateHighlight();
     }
+
+    _dataGridSelectedNodeChanged(event)
+    {
+        this._updateHighlight();
+    }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -88,12 +88,12 @@
             columns[column].sortable = true;
 
         this._dataGrid = new WebInspector.TimelineDataGrid(columns);
-        this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this);
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
         this._dataGrid.sortDelegate = this;
         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("network-timeline-view-sort", "requestSent");
         this._dataGrid.sortOrderSetting = new WebInspector.Setting("network-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
 
+        this.setupDataGrid(this._dataGrid);
+
         this.element.classList.add("network");
         this.addSubview(this._dataGrid);
 
@@ -139,11 +139,6 @@
         this._dataGrid.closed();
     }
 
-    matchTreeElementAgainstCustomFilters(treeElement)
-    {
-        return this._dataGrid.treeElementMatchesActiveScopeFilters(treeElement);
-    }
-
     reset()
     {
         super.reset();
@@ -235,14 +230,4 @@
 
         this.needsLayout();
     }
-
-    _dataGridFiltersDidChange(event)
-    {
-        // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
-    }
-
-    _dataGridNodeSelected(event)
-    {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
-    }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -45,8 +45,9 @@
         columns.graph.headerView = this._timelineRuler;
 
         this._dataGrid = new WebInspector.DataGrid(columns);
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
 
+        this.setupDataGrid(this._dataGrid);
+
         this._currentTimeMarker = new WebInspector.TimelineMarker(0, WebInspector.TimelineMarker.Type.CurrentTime);
         this._timelineRuler.addMarker(this._currentTimeMarker);
 
@@ -294,11 +295,6 @@
         this._timelineRuler.addMarker(event.data.marker);
     }
 
-    _dataGridNodeSelected(event)
-    {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
-    }
-
     _recordingReset(event)
     {
         this._timelineRuler.clearMarkers();

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -77,10 +77,11 @@
             columns[column].sortable = true;
 
         this._dataGrid = new WebInspector.TimelineDataGrid(columns);
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("rendering-frame-timeline-view-sort", "startTime");
         this._dataGrid.sortOrderSetting = new WebInspector.Setting("rendering-frame-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
 
+        this.setupDataGrid(this._dataGrid);
+
         this.element.classList.add("rendering-frame");
         this.addSubview(this._dataGrid);
 
@@ -151,22 +152,24 @@
         return pathComponents;
     }
 
-    matchTreeElementAgainstCustomFilters(treeElement)
+    get filterStartTime()
     {
-        console.assert(this._scopeBar.selectedItems.length === 1);
-        var selectedScopeBarItem = this._scopeBar.selectedItems[0];
-        if (!selectedScopeBarItem || selectedScopeBarItem.id === WebInspector.RenderingFrameTimelineView.DurationFilter.All)
-            return true;
+        let records = this.representedObject.records;
+        let startIndex = this.startTime;
+        if (startIndex >= records.length)
+            return Infinity;
 
-        while (treeElement && !(treeElement.record instanceof WebInspector.RenderingFrameTimelineRecord))
-            treeElement = treeElement.parent;
+        return records[startIndex].startTime;
+    }
 
-        console.assert(treeElement, "Cannot apply duration filter: no RenderingFrameTimelineRecord found.");
-        if (!treeElement)
-            return false;
+    get filterEndTime()
+    {
+        let records = this.representedObject.records;
+        let endIndex = this.endTime - 1;
+        if (endIndex >= records.length)
+            return Infinity;
 
-        var minimumDuration = selectedScopeBarItem.id === WebInspector.RenderingFrameTimelineView.DurationFilter.OverOneMillisecond ? 0.001 : 0.015;
-        return treeElement.record.duration > minimumDuration;
+        return records[endIndex].endTime;
     }
 
     reset()
@@ -195,6 +198,28 @@
         return null;
     }
 
+    matchDataGridNodeAgainstCustomFilters(node)
+    {
+        if (!super.matchDataGridNodeAgainstCustomFilters(node))
+            return false;
+
+        console.assert(node instanceof WebInspector.TimelineDataGridNode);
+        console.assert(this._scopeBar.selectedItems.length === 1);
+        let selectedScopeBarItem = this._scopeBar.selectedItems[0];
+        if (!selectedScopeBarItem || selectedScopeBarItem.id === WebInspector.RenderingFrameTimelineView.DurationFilter.All)
+            return true;
+
+        while (node && !(node.record instanceof WebInspector.RenderingFrameTimelineRecord))
+            node = node.parent;
+
+        console.assert(node, "Cannot apply duration filter: no RenderingFrameTimelineRecord found.");
+        if (!node)
+            return false;
+
+        let minimumDuration = selectedScopeBarItem.id === WebInspector.RenderingFrameTimelineView.DurationFilter.OverOneMillisecond ? 0.001 : 0.015;
+        return node.record.duration > minimumDuration;
+    }
+
     layout()
     {
         this._processPendingRecords();
@@ -264,15 +289,10 @@
         this.needsLayout();
     }
 
-    _dataGridNodeSelected(event)
+    _scopeBarSelectionDidChange()
     {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
+        this.filterDidChange();
     }
-
-    _scopeBarSelectionDidChange(event)
-    {
-        // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
-    }
 };
 
 WebInspector.RenderingFrameTimelineView.DurationFilter = {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -146,6 +146,15 @@
         return [WebInspector.ResourceTreeElement.ResourceIconStyleClassName, this.resource.type];
     }
 
+    // Protected
+
+    filterableDataForColumn(columnIdentifier)
+    {
+        if (columnIdentifier === "name")
+            return this._resource.url;
+        return super.filterableDataForColumn(columnIdentifier);
+    }
+
     // Private
 
     _createNameCellDocumentFragment()

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptClusterTimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptClusterTimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptClusterTimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -71,8 +71,9 @@
     set currentTime(x) { this._contentViewContainer.currentContentView.currentTime = x; }
     get navigationSidebarTreeOutline() { return this._contentViewContainer.currentContentView.navigationSidebarTreeOutline; }
     reset() { return this._contentViewContainer.currentContentView.reset(); }
+    updateFilter(filters) { return this._contentViewContainer.currentContentView.updateFilter(filters); }
     filterDidChange() { return this._contentViewContainer.currentContentView.filterDidChange(); }
-    matchTreeElementAgainstCustomFilters(treeElement) { return this._contentViewContainer.currentContentView.matchTreeElementAgainstCustomFilters(treeElement); }
+    matchDataGridNodeAgainstCustomFilters(node) { return this._contentViewContainer.currentContentView.matchDataGridNodeAgainstCustomFilters(node); }
 
     // Public
 
@@ -196,8 +197,6 @@
         currentContentView.startTime = previousContentView.startTime;
         currentContentView.endTime = previousContentView.endTime;
         currentContentView.currentTime = previousContentView.currentTime;
-
-        // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
     }
 };
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptDetailsTimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptDetailsTimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptDetailsTimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -72,12 +72,12 @@
             columns[column].sortable = true;
 
         this._dataGrid = new WebInspector.ScriptTimelineDataGrid(columns);
-        this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this);
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
         this._dataGrid.sortDelegate = this;
         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("script-timeline-view-sort", "startTime");
         this._dataGrid.sortOrderSetting = new WebInspector.Setting("script-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
 
+        this.setupDataGrid(this._dataGrid);
+
         this.element.classList.add("script");
         this.addSubview(this._dataGrid);
 
@@ -236,14 +236,4 @@
     {
         this.needsLayout();
     }
-
-    _dataGridFiltersDidChange(event)
-    {
-        // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
-    }
-
-    _dataGridNodeSelected(event)
-    {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
-    }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineDataGridNode.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineDataGridNode.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineDataGridNode.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -156,6 +156,16 @@
         return super.createCellContent(columnIdentifier, cell);
     }
 
+    // Protected
+
+    filterableDataForColumn(columnIdentifier)
+    {
+        if (columnIdentifier === "name")
+            return [this.displayName(), this.subtitle];
+
+        return super.filterableDataForColumn(columnIdentifier);
+    }
+
     // Private
 
     _createNameCellDocumentFragment(cellElement)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -25,17 +25,17 @@
 
 WebInspector.TimelineDataGrid = class TimelineDataGrid extends WebInspector.DataGrid
 {
-    constructor(columns, treeOutline, delegate, editCallback, deleteCallback)
+    constructor(columns, treeOutline, synchronizerDelegate, editCallback, deleteCallback)
     {
         super(columns, editCallback, deleteCallback);
 
         if (treeOutline)
-            this._treeOutlineDataGridSynchronizer = new WebInspector.TreeOutlineDataGridSynchronizer(treeOutline, this, delegate);
+            this._treeOutlineDataGridSynchronizer = new WebInspector.TreeOutlineDataGridSynchronizer(treeOutline, this, synchronizerDelegate);
 
         this.element.classList.add("timeline");
 
-        this._filterableColumns = [];
         this._sortDelegate = null;
+        this._scopeBarColumns = [];
 
         // Check if any of the cells can be filtered.
         for (var [identifier, column] of this.columns) {
@@ -44,12 +44,12 @@
             if (!scopeBar)
                 continue;
 
-            this._filterableColumns.push(identifier);
+            this._scopeBarColumns.push(identifier);
             scopeBar.columnIdentifier = identifier;
             scopeBar.addEventListener(WebInspector.ScopeBar.Event.SelectionChanged, this._scopeBarSelectedItemsDidChange, this);
         }
 
-        if (this._filterableColumns.length > 1) {
+        if (this._scopeBarColumns.length > 1) {
             console.error("Creating a TimelineDataGrid with more than one filterable column is not yet supported.");
             return;
         }
@@ -149,31 +149,6 @@
         return null;
     }
 
-    treeElementMatchesActiveScopeFilters(treeElement)
-    {
-        if (!this._treeOutlineDataGridSynchronizer)
-            return false;
-
-        var dataGridNode = this._treeOutlineDataGridSynchronizer.dataGridNodeForTreeElement(treeElement);
-        console.assert(dataGridNode);
-
-        for (var identifier of this._filterableColumns) {
-            var scopeBar = this.columns.get(identifier).scopeBar;
-            if (!scopeBar || scopeBar.defaultItem.selected)
-                continue;
-
-            var value = dataGridNode.data[identifier];
-            var matchesFilter = scopeBar.selectedItems.some(function(scopeBarItem) {
-                return scopeBarItem.value === value;
-            });
-
-            if (!matchesFilter)
-                return false;
-        }
-
-        return true;
-    }
-
     addRowInSortOrder(treeElement, dataGridNode, parentTreeElementOrDataGridNode)
     {
         let parentDataGridNode;
@@ -235,6 +210,29 @@
         this._scheduledDataGridNodeRefreshIdentifier = requestAnimationFrame(this._refreshDirtyDataGridNodes.bind(this));
     }
 
+    hasCustomFilters()
+    {
+        return true;
+    }
+
+    matchNodeAgainstCustomFilters(node)
+    {
+        if (!super.matchNodeAgainstCustomFilters(node))
+            return false;
+
+        for (let identifier of this._scopeBarColumns) {
+            let scopeBar = this.columns.get(identifier).scopeBar;
+            if (!scopeBar || scopeBar.defaultItem.selected)
+                continue;
+
+            let value = node.data[identifier];
+            if (!scopeBar.selectedItems.some((scopeBarItem) => scopeBarItem.value === value))
+                return false;
+        }
+
+        return true;
+    }
+
     // Private
 
     _refreshDirtyDataGridNodes()
@@ -420,23 +418,9 @@
         return (value1 < value2 ? -1 : (value1 > value2 ? 1 : 0)) * sortDirection;
     }
 
-    _updateScopeBarForcedVisibility()
-    {
-        for (var identifier of this._filterableColumns) {
-            var scopeBar = this.columns.get(identifier).scopeBar;
-            if (scopeBar) {
-                this.element.classList.toggle(WebInspector.TimelineDataGrid.HasNonDefaultFilterStyleClassName, scopeBar.hasNonDefaultItemSelected());
-                break;
-            }
-        }
-    }
-
     _scopeBarSelectedItemsDidChange(event)
     {
-        this._updateScopeBarForcedVisibility();
-
-        var columnIdentifier = event.target.columnIdentifier;
-        this.dispatchEventToListeners(WebInspector.TimelineDataGrid.Event.FiltersDidChange, {columnIdentifier});
+        this.filterDidChange();
     }
 
     _dataGridSelectedNodeChanged(event)
@@ -564,11 +548,8 @@
     }
 };
 
+WebInspector.TimelineDataGrid.WasExpandedDuringFilteringSymbol = Symbol("was-expanded-during-filtering");
+
 WebInspector.TimelineDataGrid.HasNonDefaultFilterStyleClassName = "has-non-default-filter";
 WebInspector.TimelineDataGrid.DelayedPopoverShowTimeout = 250;
 WebInspector.TimelineDataGrid.DelayedPopoverHideContentClearTimeout = 500;
-
-WebInspector.TimelineDataGrid.Event = {
-    FiltersDidChange: "timelinedatagrid-filters-did-change"
-};
-

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -364,4 +364,16 @@
 
         return true;
     }
+
+    filterableDataForColumn(columnIdentifier)
+    {
+        let value = this.data[columnIdentifier];
+        if (value instanceof WebInspector.SourceCodeLocation)
+            return value.displayLocationString();
+
+        if (value instanceof WebInspector.CallFrame)
+            return [value.functionName, value.sourceCodeLocation.displayLocationString()];
+
+        return super.filterableDataForColumn(columnIdentifier);
+    }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -53,6 +53,7 @@
 
         this._filterBarNavigationItem = new WebInspector.FilterBarNavigationItem;
         this._filterBarNavigationItem.filterBar.placeholder = WebInspector.UIString("Filter Records");
+        this._filterBarNavigationItem.filterBar.addEventListener(WebInspector.FilterBar.Event.FilterDidChange, this._filterDidChange, this);
         this._timelineContentBrowser.navigationBar.addNavigationItem(this._filterBarNavigationItem);
         this.addSubview(this._timelineContentBrowser);
 
@@ -85,6 +86,8 @@
         WebInspector.ContentView.addEventListener(WebInspector.ContentView.Event.SelectionPathComponentsDidChange, this._contentViewSelectionPathComponentDidChange, this);
         WebInspector.ContentView.addEventListener(WebInspector.ContentView.Event.SupplementalRepresentedObjectsDidChange, this._contentViewSupplementalRepresentedObjectsDidChange, this);
 
+        WebInspector.TimelineView.addEventListener(WebInspector.TimelineView.Event.RecordWasFiltered, this._recordWasFiltered, this);
+
         for (let instrument of this._recording.instruments)
             this._instrumentAdded(instrument);
 
@@ -215,94 +218,6 @@
         this._timelineContentBrowser.goForward();
     }
 
-    filterDidChange()
-    {
-        if (!this.currentTimelineView)
-            return;
-
-        this.currentTimelineView.filterDidChange();
-    }
-
-    recordWasFiltered(record, filtered)
-    {
-        if (!this.currentTimelineView)
-            return;
-
-        this._timelineOverview.recordWasFiltered(this.currentTimelineView.representedObject, record, filtered);
-    }
-
-    matchTreeElementAgainstCustomFilters(treeElement)
-    {
-        if (this.currentTimelineView && !this.currentTimelineView.matchTreeElementAgainstCustomFilters(treeElement))
-            return false;
-
-        let startTime = this._timelineOverview.selectionStartTime;
-        let endTime = startTime + this._timelineOverview.selectionDuration;
-        let currentTime = this._currentTime || this._recording.startTime;
-
-        if (this._timelineOverview.viewMode === WebInspector.TimelineOverview.ViewMode.RenderingFrames) {
-            console.assert(this._renderingFrameTimeline);
-
-            if (this._renderingFrameTimeline && this._renderingFrameTimeline.records.length) {
-                let records = this._renderingFrameTimeline.records;
-                let startIndex = this._timelineOverview.timelineRuler.snapInterval ? startTime : Math.floor(startTime);
-                if (startIndex >= records.length)
-                    return false;
-
-                let endIndex = this._timelineOverview.timelineRuler.snapInterval ? endTime - 1: Math.floor(endTime);
-                endIndex = Math.min(endIndex, records.length - 1);
-                console.assert(startIndex <= endIndex, startIndex);
-
-                startTime = records[startIndex].startTime;
-                endTime = records[endIndex].endTime;
-            }
-        }
-
-        function checkTimeBounds(itemStartTime, itemEndTime)
-        {
-            itemStartTime = itemStartTime || currentTime;
-            itemEndTime = itemEndTime || currentTime;
-
-            return startTime <= itemEndTime && itemStartTime <= endTime;
-        }
-
-        if (treeElement instanceof WebInspector.ResourceTreeElement) {
-            var resource = treeElement.resource;
-            return checkTimeBounds(resource.requestSentTimestamp, resource.finishedOrFailedTimestamp);
-        }
-
-        if (treeElement instanceof WebInspector.SourceCodeTimelineTreeElement) {
-            var sourceCodeTimeline = treeElement.sourceCodeTimeline;
-
-            // Do a quick check of the timeline bounds before we check each record.
-            if (!checkTimeBounds(sourceCodeTimeline.startTime, sourceCodeTimeline.endTime))
-                return false;
-
-            for (var record of sourceCodeTimeline.records) {
-                if (checkTimeBounds(record.startTime, record.endTime))
-                    return true;
-            }
-
-            return false;
-        }
-
-        if (treeElement instanceof WebInspector.ProfileNodeTreeElement) {
-            var profileNode = treeElement.profileNode;
-            if (checkTimeBounds(profileNode.startTime, profileNode.endTime))
-                return true;
-
-            return false;
-        }
-
-        if (treeElement instanceof WebInspector.TimelineRecordTreeElement) {
-            var record = treeElement.record;
-            return checkTimeBounds(record.startTime, record.endTime);
-        }
-
-        console.error("Unknown TreeElement, can't filter by time.");
-        return true;
-    }
-
     // ContentBrowser delegate
 
     contentBrowserTreeElementForRepresentedObject(contentBrowser, representedObject)
@@ -470,9 +385,6 @@
         if (this._timelineOverview.timelineRuler.entireRangeSelected)
             this._updateTimelineViewSelection(this._overviewTimelineView);
 
-        // Filter records on new recording times.
-        // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
-
         // Force a layout now since we are already in an animation frame and don't need to delay it until the next.
         this._timelineOverview.updateLayoutIfNeeded();
         if (this.currentTimelineView)
@@ -699,18 +611,6 @@
             this._selectedTimeRangePathComponent = selectedPathComponent;
             this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
         }
-
-        // Delay until the next frame to stay in sync with the current timeline view's time-based layout changes.
-        requestAnimationFrame(function() {
-            var selectedTreeElement = this.currentTimelineView && this.currentTimelineView.navigationSidebarTreeOutline ? this.currentTimelineView.navigationSidebarTreeOutline.selectedTreeElement : null;
-            var selectionWasHidden = selectedTreeElement && selectedTreeElement.hidden;
-
-            // Filter records on new timeline selection.
-            // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
-
-            if (selectedTreeElement && selectedTreeElement.hidden !== selectionWasHidden)
-                this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
-        }.bind(this));
     }
 
     _recordSelected(event)
@@ -796,4 +696,22 @@
 
         this._updateTimelineOverviewHeight();
     }
+
+    _filterDidChange()
+    {
+        if (!this.currentTimelineView)
+            return;
+
+        this.currentTimelineView.updateFilter(this._filterBarNavigationItem.filterBar.filters);
+    }
+
+    _recordWasFiltered(event)
+    {
+        if (event.target !== this.currentTimelineView)
+            return;
+
+        let record = event.data.record;
+        let filtered = event.data.filtered;
+        this._timelineOverview.recordWasFiltered(this.currentTimelineView.representedObject, record, filtered);
+    }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js (200066 => 200067)


--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js	2016-04-26 00:50:07 UTC (rev 200066)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineView.js	2016-04-26 01:00:17 UTC (rev 200067)
@@ -43,6 +43,11 @@
 
     // Public
 
+    get navigationItems()
+    {
+        return this._scopeBar ? [this._scopeBar] : [];
+    }
+
     get navigationSidebarTreeOutlineScopeBar()
     {
         return this._scopeBar;
@@ -85,6 +90,7 @@
 
         this._startTime = x;
 
+        this._filterTimesDidChange();
         this.needsLayout();
     }
 
@@ -102,6 +108,7 @@
 
         this._endTime = x;
 
+        this._filterTimesDidChange();
         this.needsLayout();
     }
 
@@ -128,20 +135,47 @@
             return this._startTime - wiggleTime <= currentTime && currentTime <= this._endTime + wiggleTime;
         }
 
-        if (checkIfLayoutIsNeeded.call(this, oldCurrentTime) || checkIfLayoutIsNeeded.call(this, this._currentTime))
+        if (checkIfLayoutIsNeeded.call(this, oldCurrentTime) || checkIfLayoutIsNeeded.call(this, this._currentTime)) {
+            this._filterTimesDidChange();
             this.needsLayout();
+        }
     }
 
-    reset()
+    get filterStartTime()
     {
         // Implemented by sub-classes if needed.
+        return this.startTime;
     }
 
-    filterDidChange()
+    get filterEndTime()
     {
         // Implemented by sub-classes if needed.
+        return this.endTime;
     }
 
+    setupDataGrid(dataGrid)
+    {
+        console.assert(!this._timelineDataGrid);
+
+        this._timelineDataGrid = dataGrid;
+        this._timelineDataGrid.filterDelegate = this;
+        this._timelineDataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, () => {
+            this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
+        });
+
+        this._timelineDataGrid.addEventListener(WebInspector.DataGrid.Event.NodeWasFiltered, (event) => {
+            let node = event.data.node;
+            if (!(node instanceof WebInspector.TimelineDataGridNode))
+                return;
+
+            this.dispatchEventToListeners(WebInspector.TimelineView.Event.RecordWasFiltered, {record: node.record, filtered: node.hidden});
+        });
+
+        this._timelineDataGrid.addEventListener(WebInspector.DataGrid.Event.FilterDidChange, (event) => {
+            this.filterDidChange();
+        });
+    }
+
     selectRecord(record)
     {
         if (!this._timelineDataGrid)
@@ -166,17 +200,25 @@
         dataGridNode.revealAndSelect();
     }
 
-    matchTreeElementAgainstCustomFilters(treeElement)
+    reset()
     {
         // Implemented by sub-classes if needed.
-        return true;
     }
 
-    filterUpdated()
+    updateFilter(filters)
     {
-        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
+        if (!this._timelineDataGrid)
+            return;
+
+        this._timelineDataGrid.filterText = filters ? filters.text : "";
     }
 
+    matchDataGridNodeAgainstCustomFilters(node)
+    {
+        // Implemented by sub-classes if needed.
+        return true;
+    }
+
     needsLayout()
     {
         // FIXME: needsLayout can be removed once <https://webkit.org/b/150741> is fixed.
@@ -186,10 +228,92 @@
         super.needsLayout();
     }
 
+    // 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 WebInspector.ResourceTimelineDataGridNode) {
+            let resource = node.resource;
+            return checkTimeBounds(resource.requestSentTimestamp, resource.finishedOrFailedTimestamp);
+        }
+
+        if (node instanceof WebInspector.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 WebInspector.ProfileNodeDataGridNode) {
+            let profileNode = node.profileNode;
+            if (checkTimeBounds(profileNode.startTime, profileNode.endTime))
+                return true;
+
+            return false;
+        }
+
+        if (node instanceof WebInspector.TimelineDataGridNode) {
+            let record = node.record;
+            return checkTimeBounds(record.startTime, record.endTime);
+        }
+
+        console.error("Unknown DataGridNode, can't filter by time.");
+        return true;
+    }
+
     // Protected
 
     userSelectedRecordFromOverview(timelineRecord)
     {
         // Implemented by sub-classes if needed.
     }
+
+    filterDidChange()
+    {
+        // Implemented by sub-classes if needed.
+    }
+
+    // Private
+
+    _filterTimesDidChange()
+    {
+        if (!this._timelineDataGrid || this._updateFilterTimeout)
+            return;
+
+        function delayedWork()
+        {
+            this._updateFilterTimeout = undefined;
+            this._timelineDataGrid.filterDidChange();
+        }
+
+        this._updateFilterTimeout = setTimeout(delayedWork.bind(this), 0);
+    }
 };
+
+WebInspector.TimelineView.Event = {
+    RecordWasFiltered: "record-was-filtered"
+};
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to