summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Views/ProfileView.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Views/ProfileView.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/ProfileView.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Views/ProfileView.js308
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",
+};