diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Views/ProfileView.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/ProfileView.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Views/ProfileView.js | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/ProfileView.js b/Source/WebInspectorUI/UserInterface/Views/ProfileView.js new file mode 100644 index 000000000..b6a503a14 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Views/ProfileView.js @@ -0,0 +1,308 @@ +/* +* Copyright (C) 2016 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.ProfileView = class ProfileView extends WebInspector.ContentView +{ + constructor(callingContextTree, extraArguments) + { + super(callingContextTree); + + console.assert(callingContextTree instanceof WebInspector.CallingContextTree); + + this._startTime = 0; + this._endTime = Infinity; + this._callingContextTree = callingContextTree; + + this._hoveredDataGridNode = null; + + this.element.classList.add("profile"); + + let columns = { + totalTime: { + title: WebInspector.UIString("Total Time"), + width: "120px", + sortable: true, + aligned: "right", + }, + selfTime: { + title: WebInspector.UIString("Self Time"), + width: "75px", + sortable: true, + aligned: "right", + }, + function: { + title: WebInspector.UIString("Function"), + disclosure: true, + }, + }; + + this._dataGrid = new WebInspector.DataGrid(columns); + this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SortChanged, this._dataGridSortChanged, this); + this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this); + this._dataGrid.addEventListener(WebInspector.DataGrid.Event.ExpandedNode, this._dataGridNodeExpanded, this); + this._dataGrid.element.addEventListener("mouseover", this._mouseOverDataGrid.bind(this)); + this._dataGrid.element.addEventListener("mouseleave", this._mouseLeaveDataGrid.bind(this)); + this._dataGrid.indentWidth = 20; + this._dataGrid.sortColumnIdentifier = "totalTime"; + this._dataGrid.sortOrder = WebInspector.DataGrid.SortOrder.Descending; + this._dataGrid.createSettings("profile-view"); + + // Currently we create a new ProfileView for each CallingContextTree, so + // to share state between them, use a common shared data object. + this._sharedData = extraArguments; + + this.addSubview(this._dataGrid); + } + + // Public + + get callingContextTree() { return this._callingContextTree; } + get startTime() { return this._startTime; } + get endTime() { return this._endTime; } + get dataGrid() { return this._dataGrid; } + + setStartAndEndTime(startTime, endTime) + { + console.assert(startTime >= 0); + console.assert(endTime >= 0); + console.assert(startTime <= endTime); + + this._startTime = startTime; + this._endTime = endTime; + + // FIXME: It would be ideal to update the existing tree, maintaining nodes that were expanded. + // For now just recreate the tree for the new time range. + + this._recreate(); + } + + hasFocusNodes() + { + if (!this._profileDataGridTree) + return false; + return this._profileDataGridTree.focusNodes.length > 0; + } + + clearFocusNodes() + { + if (!this._profileDataGridTree) + return; + this._profileDataGridTree.clearFocusNodes(); + } + + get scrollableElements() + { + return [this._dataGrid.scrollContainer]; + } + + // Protected + + get selectionPathComponents() + { + let pathComponents = []; + + if (this._profileDataGridTree) { + for (let profileDataGridNode of this._profileDataGridTree.focusNodes) { + let displayName = profileDataGridNode.displayName(); + let className = profileDataGridNode.iconClassName(); + let pathComponent = new WebInspector.HierarchicalPathComponent(displayName, className, profileDataGridNode); + pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.Clicked, this._pathComponentClicked, this); + pathComponents.push(pathComponent); + } + } + + return pathComponents; + } + + // Private + + _recreate() + { + let hadFocusNodes = this.hasFocusNodes(); + + let sortComparator = WebInspector.ProfileDataGridTree.buildSortComparator(this._dataGrid.sortColumnIdentifier, this._dataGrid.sortOrder); + this._profileDataGridTree = new WebInspector.ProfileDataGridTree(this._callingContextTree, this._startTime, this._endTime, sortComparator); + this._profileDataGridTree.addEventListener(WebInspector.ProfileDataGridTree.Event.FocusChanged, this._dataGridTreeFocusChanged, this); + this._profileDataGridTree.addEventListener(WebInspector.ProfileDataGridTree.Event.ModifiersChanged, this._dataGridTreeModifiersChanged, this); + this._repopulateDataGridFromTree(); + + if (hadFocusNodes) + this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange); + } + + _repopulateDataGridFromTree() + { + this._dataGrid.removeChildren(); + + for (let child of this._profileDataGridTree.children) + this._dataGrid.appendChild(child); + + this._restoreSharedState(); + } + + _restoreSharedState() + { + const skipHidden = false; + const stayWithin = this._dataGrid; + const dontPopulate = true; + + if (this._sharedData.selectedNodeHash) { + let nodeToSelect = this._dataGrid.findNode((node) => node.callingContextTreeNode.hash === this._sharedData.selectedNodeHash, skipHidden, stayWithin, dontPopulate); + if (nodeToSelect) + nodeToSelect.revealAndSelect(); + } + } + + _pathComponentClicked(event) + { + if (!event.data.pathComponent) + return; + + let profileDataGridNode = event.data.pathComponent.representedObject; + if (profileDataGridNode === this._profileDataGridTree.currentFocusNode) + return; + + this._profileDataGridTree.rollbackFocusNode(event.data.pathComponent.representedObject); + } + + _dataGridTreeFocusChanged(event) + { + this._repopulateDataGridFromTree(); + this._profileDataGridTree.refresh(); + + this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange); + } + + _dataGridTreeModifiersChanged(event) + { + this._profileDataGridTree.refresh(); + } + + _dataGridSortChanged() + { + if (!this._profileDataGridTree) + return; + + this._profileDataGridTree.sortComparator = WebInspector.ProfileDataGridTree.buildSortComparator(this._dataGrid.sortColumnIdentifier, this._dataGrid.sortOrder); + this._repopulateDataGridFromTree(); + } + + _dataGridNodeSelected(event) + { + let oldSelectedNode = event.data.oldSelectedNode; + if (oldSelectedNode) { + this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Selected, oldSelectedNode); + oldSelectedNode.forEachChildInSubtree((node) => this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Selected, node)); + } + + let newSelectedNode = this._dataGrid.selectedNode; + if (newSelectedNode) { + this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Selected, newSelectedNode); + newSelectedNode.forEachChildInSubtree((node) => this._appendGuidanceElement(WebInspector.ProfileView.GuidanceType.Selected, node, newSelectedNode)); + + this._sharedData.selectedNodeHash = newSelectedNode.callingContextTreeNode.hash; + } + } + + _dataGridNodeExpanded(event) + { + let expandedNode = event.data.dataGridNode; + + if (this._dataGrid.selectedNode) { + if (expandedNode.isInSubtreeOfNode(this._dataGrid.selectedNode)) + expandedNode.forEachImmediateChild((node) => this._appendGuidanceElement(WebInspector.ProfileView.GuidanceType.Selected, node, this._dataGrid.selectedNode)); + } + + if (this._hoveredDataGridNode) { + if (expandedNode.isInSubtreeOfNode(this._hoveredDataGridNode)) + expandedNode.forEachImmediateChild((node) => this._appendGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, node, this._hoveredDataGridNode)); + } + } + + _mouseOverDataGrid(event) + { + let hoveredDataGridNode = this._dataGrid.dataGridNodeFromNode(event.target); + if (hoveredDataGridNode === this._hoveredDataGridNode) + return; + + if (this._hoveredDataGridNode) { + this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, this._hoveredDataGridNode); + this._hoveredDataGridNode.forEachChildInSubtree((node) => this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, node)); + } + + this._hoveredDataGridNode = hoveredDataGridNode; + + if (this._hoveredDataGridNode) { + this._appendGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, this._hoveredDataGridNode, this._hoveredDataGridNode); + this._hoveredDataGridNode.forEachChildInSubtree((node) => this._appendGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, node, this._hoveredDataGridNode)); + } + } + + _mouseLeaveDataGrid(event) + { + if (!this._hoveredDataGridNode) + return; + + this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, this._hoveredDataGridNode); + this._hoveredDataGridNode.forEachChildInSubtree((node) => this._removeGuidanceElement(WebInspector.ProfileView.GuidanceType.Hover, node)); + + this._hoveredDataGridNode = null; + } + + _guidanceElementKey(type) + { + return "guidance-element-" + type; + } + + _removeGuidanceElement(type, node) + { + let key = this._guidanceElementKey(type); + let element = node.elementWithColumnIdentifier("function"); + if (!element || !element[key]) + return; + + element[key].remove(); + element[key] = null; + } + + _appendGuidanceElement(type, node, baseElement) + { + let depth = baseElement.depth; + let guidanceMarkerLeft = depth ? (depth * this._dataGrid.indentWidth) + 1.5 : 7.5; + + let key = this._guidanceElementKey(type); + let element = node.elementWithColumnIdentifier("function"); + let guidanceElement = element[key] || element.appendChild(document.createElement("div")); + element[key] = guidanceElement; + guidanceElement.classList.add("guidance", type); + guidanceElement.classList.toggle("base", node === baseElement); + guidanceElement.style.left = guidanceMarkerLeft + "px"; + } +}; + +WebInspector.ProfileView.GuidanceType = { + Selected: "selected", + Hover: "hover", +}; |