| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 this.viewSelectElement.addEventListener("change", this._changeView.bind(this
), false); | 49 this.viewSelectElement.addEventListener("change", this._changeView.bind(this
), false); |
| 50 this.view = "Heavy"; | 50 this.view = "Heavy"; |
| 51 | 51 |
| 52 var heavyViewOption = document.createElement("option"); | 52 var heavyViewOption = document.createElement("option"); |
| 53 heavyViewOption.label = WebInspector.UIString("Heavy (Bottom Up)"); | 53 heavyViewOption.label = WebInspector.UIString("Heavy (Bottom Up)"); |
| 54 var treeViewOption = document.createElement("option"); | 54 var treeViewOption = document.createElement("option"); |
| 55 treeViewOption.label = WebInspector.UIString("Tree (Top Down)"); | 55 treeViewOption.label = WebInspector.UIString("Tree (Top Down)"); |
| 56 this.viewSelectElement.appendChild(heavyViewOption); | 56 this.viewSelectElement.appendChild(heavyViewOption); |
| 57 this.viewSelectElement.appendChild(treeViewOption); | 57 this.viewSelectElement.appendChild(treeViewOption); |
| 58 | 58 |
| 59 this.percentButton = document.createElement("button"); | 59 this.percentButton = new WebInspector.StatusBarButton("", "percent-time-stat
us-bar-item"); |
| 60 this.percentButton.className = "percent-time-status-bar-item status-bar-item
"; | |
| 61 this.percentButton.addEventListener("click", this._percentClicked.bind(this)
, false); | 60 this.percentButton.addEventListener("click", this._percentClicked.bind(this)
, false); |
| 62 | 61 |
| 63 this.focusButton = document.createElement("button"); | 62 this.focusButton = new WebInspector.StatusBarButton(WebInspector.UIString("F
ocus selected function."), "focus-profile-node-status-bar-item"); |
| 64 this.focusButton.title = WebInspector.UIString("Focus selected function."); | |
| 65 this.focusButton.className = "focus-profile-node-status-bar-item status-bar-
item"; | |
| 66 this.focusButton.disabled = true; | 63 this.focusButton.disabled = true; |
| 67 this.focusButton.addEventListener("click", this._focusClicked.bind(this), fa
lse); | 64 this.focusButton.addEventListener("click", this._focusClicked.bind(this), fa
lse); |
| 68 | 65 |
| 69 this.excludeButton = document.createElement("button"); | 66 this.excludeButton = new WebInspector.StatusBarButton(WebInspector.UIString(
"Exclude selected function."), "exclude-profile-node-status-bar-item"); |
| 70 this.excludeButton.title = WebInspector.UIString("Exclude selected function.
"); | |
| 71 this.excludeButton.className = "exclude-profile-node-status-bar-item status-
bar-item"; | |
| 72 this.excludeButton.disabled = true; | 67 this.excludeButton.disabled = true; |
| 73 this.excludeButton.addEventListener("click", this._excludeClicked.bind(this)
, false); | 68 this.excludeButton.addEventListener("click", this._excludeClicked.bind(this)
, false); |
| 74 | 69 |
| 75 this.resetButton = document.createElement("button"); | 70 this.resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("R
estore all functions."), "reset-profile-status-bar-item"); |
| 76 this.resetButton.title = WebInspector.UIString("Restore all functions."); | 71 this.resetButton.visible = false; |
| 77 this.resetButton.className = "reset-profile-status-bar-item status-bar-item
hidden"; | |
| 78 this.resetButton.addEventListener("click", this._resetClicked.bind(this), fa
lse); | 72 this.resetButton.addEventListener("click", this._resetClicked.bind(this), fa
lse); |
| 79 | 73 |
| 80 this.profile = profile; | 74 this.profile = profile; |
| 81 | 75 |
| 82 this.profileDataGridTree = this.bottomUpProfileDataGridTree; | 76 this.profileDataGridTree = this.bottomUpProfileDataGridTree; |
| 83 this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyCompa
rator("selfTime", false)); | 77 this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyCompa
rator("selfTime", false)); |
| 84 | 78 |
| 85 this.refresh(); | 79 this.refresh(); |
| 86 | 80 |
| 87 this._updatePercentButton(); | 81 this._updatePercentButton(); |
| 88 } | 82 } |
| 89 | 83 |
| 90 WebInspector.ProfileView.prototype = { | 84 WebInspector.ProfileView.prototype = { |
| 91 get statusBarItems() | 85 get statusBarItems() |
| 92 { | 86 { |
| 93 return [this.viewSelectElement, this.percentButton, this.focusButton, th
is.excludeButton, this.resetButton]; | 87 return [this.viewSelectElement, this.percentButton.element, this.focusBu
tton.element, this.excludeButton.element, this.resetButton.element]; |
| 94 }, | 88 }, |
| 95 | 89 |
| 96 get profile() | 90 get profile() |
| 97 { | 91 { |
| 98 return this._profile; | 92 return this._profile; |
| 99 }, | 93 }, |
| 100 | 94 |
| 101 set profile(profile) | 95 set profile(profile) |
| 102 { | 96 { |
| 103 this._profile = profile; | 97 this._profile = profile; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 get bottomUpTree() | 135 get bottomUpTree() |
| 142 { | 136 { |
| 143 if (!this._bottomUpTree) { | 137 if (!this._bottomUpTree) { |
| 144 this._bottomUpTree = WebInspector.BottomUpTreeFactory.create(this.pr
ofile.head); | 138 this._bottomUpTree = WebInspector.BottomUpTreeFactory.create(this.pr
ofile.head); |
| 145 this._sortProfile(this._bottomUpTree); | 139 this._sortProfile(this._bottomUpTree); |
| 146 } | 140 } |
| 147 | 141 |
| 148 return this._bottomUpTree; | 142 return this._bottomUpTree; |
| 149 }, | 143 }, |
| 150 | 144 |
| 145 show: function(parentElement) |
| 146 { |
| 147 WebInspector.View.prototype.show.call(this, parentElement); |
| 148 this.dataGrid.updateWidths(); |
| 149 }, |
| 150 |
| 151 hide: function() | 151 hide: function() |
| 152 { | 152 { |
| 153 WebInspector.View.prototype.hide.call(this); | 153 WebInspector.View.prototype.hide.call(this); |
| 154 this._currentSearchResultIndex = -1; | 154 this._currentSearchResultIndex = -1; |
| 155 }, | 155 }, |
| 156 |
| 157 resize: function() |
| 158 { |
| 159 if (this.dataGrid) |
| 160 this.dataGrid.updateWidths(); |
| 161 }, |
| 156 | 162 |
| 157 refresh: function() | 163 refresh: function() |
| 158 { | 164 { |
| 159 var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.sel
ectedNode.profileNode : null; | 165 var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.sel
ectedNode.profileNode : null; |
| 160 | 166 |
| 161 this.dataGrid.removeChildren(); | 167 this.dataGrid.removeChildren(); |
| 162 | 168 |
| 163 var children = this.profileDataGridTree.children; | 169 var children = this.profileDataGridTree.children; |
| 164 var count = children.length; | 170 var count = children.length; |
| 165 | 171 |
| 166 for (var index = 0; index < count; ++index) | 172 for (var index = 0; index < count; ++index) |
| 167 this.dataGrid.appendChild(children[index]); | 173 this.dataGrid.appendChild(children[index]); |
| 168 | 174 |
| 169 if (selectedProfileNode && selectedProfileNode._dataGridNode) | 175 if (selectedProfileNode) |
| 170 selectedProfileNode._dataGridNode.selected = true; | 176 selectedProfileNode.selected = true; |
| 171 }, | 177 }, |
| 172 | 178 |
| 173 refreshVisibleData: function() | 179 refreshVisibleData: function() |
| 174 { | 180 { |
| 175 var child = this.dataGrid.children[0]; | 181 var child = this.dataGrid.children[0]; |
| 176 while (child) { | 182 while (child) { |
| 177 child.refresh(); | 183 child.refresh(); |
| 178 child = child.traverseNextNode(false, null, true); | 184 child = child.traverseNextNode(false, null, true); |
| 179 } | 185 } |
| 180 }, | 186 }, |
| 181 | 187 |
| 182 refreshShowAsPercents: function() | 188 refreshShowAsPercents: function() |
| 183 { | 189 { |
| 184 this._updatePercentButton(); | 190 this._updatePercentButton(); |
| 185 this.refreshVisibleData(); | 191 this.refreshVisibleData(); |
| 186 }, | 192 }, |
| 187 | 193 |
| 188 searchCanceled: function() | 194 searchCanceled: function() |
| 189 { | 195 { |
| 190 if (this._searchResults) { | 196 if (this._searchResults) { |
| 191 for (var i = 0; i < this._searchResults.length; ++i) { | 197 for (var i = 0; i < this._searchResults.length; ++i) { |
| 192 var profileNode = this._searchResults[i].profileNode; | 198 var profileNode = this._searchResults[i].profileNode; |
| 193 | 199 |
| 194 delete profileNode._searchMatchedSelfColumn; | 200 delete profileNode._searchMatchedSelfColumn; |
| 195 delete profileNode._searchMatchedTotalColumn; | 201 delete profileNode._searchMatchedTotalColumn; |
| 196 delete profileNode._searchMatchedCallsColumn; | 202 delete profileNode._searchMatchedCallsColumn; |
| 197 delete profileNode._searchMatchedFunctionColumn; | 203 delete profileNode._searchMatchedFunctionColumn; |
| 198 | 204 |
| 199 if (profileNode._dataGridNode) | 205 profileNode.refresh(); |
| 200 profileNode._dataGridNode.refresh(); | |
| 201 } | 206 } |
| 202 } | 207 } |
| 203 | 208 |
| 204 delete this._searchFinishedCallback; | 209 delete this._searchFinishedCallback; |
| 205 this._currentSearchResultIndex = -1; | 210 this._currentSearchResultIndex = -1; |
| 206 this._searchResults = []; | 211 this._searchResults = []; |
| 207 }, | 212 }, |
| 208 | 213 |
| 209 performSearch: function(query, finishedCallback) | 214 performSearch: function(query, finishedCallback) |
| 210 { | 215 { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 profileDataGridNode._searchMatchedCallsColumn = true; | 311 profileDataGridNode._searchMatchedCallsColumn = true; |
| 307 } | 312 } |
| 308 | 313 |
| 309 if (profileDataGridNode.functionName.hasSubstring(query, true) || pr
ofileDataGridNode.url.hasSubstring(query, true)) | 314 if (profileDataGridNode.functionName.hasSubstring(query, true) || pr
ofileDataGridNode.url.hasSubstring(query, true)) |
| 310 profileDataGridNode._searchMatchedFunctionColumn = true; | 315 profileDataGridNode._searchMatchedFunctionColumn = true; |
| 311 | 316 |
| 312 if (profileDataGridNode._searchMatchedSelfColumn || | 317 if (profileDataGridNode._searchMatchedSelfColumn || |
| 313 profileDataGridNode._searchMatchedTotalColumn || | 318 profileDataGridNode._searchMatchedTotalColumn || |
| 314 profileDataGridNode._searchMatchedAverageColumn || | 319 profileDataGridNode._searchMatchedAverageColumn || |
| 315 profileDataGridNode._searchMatchedCallsColumn || | 320 profileDataGridNode._searchMatchedCallsColumn || |
| 316 profileDataGridNode._searchMatchedFunctionColumn); | 321 profileDataGridNode._searchMatchedFunctionColumn) |
| 317 { | 322 { |
| 318 profileDataGridNode.refresh(); | 323 profileDataGridNode.refresh(); |
| 319 return true; | 324 return true; |
| 320 } | 325 } |
| 321 | 326 |
| 322 return false; | 327 return false; |
| 323 } | 328 } |
| 324 | 329 |
| 325 var current = this.dataGrid; | 330 var current = this.profileDataGridTree.children[0]; |
| 326 var ancestors = []; | |
| 327 var nextIndexes = []; | |
| 328 var startIndex = 0; | |
| 329 | 331 |
| 330 while (current) { | 332 while (current) { |
| 331 var children = current.children; | 333 if (matchesQuery(current)) { |
| 332 var childrenLength = children.length; | 334 this._searchResults.push({ profileNode: current }); |
| 333 | |
| 334 if (startIndex >= childrenLength) { | |
| 335 current = ancestors.pop(); | |
| 336 startIndex = nextIndexes.pop(); | |
| 337 continue; | |
| 338 } | 335 } |
| 339 | 336 |
| 340 for (var i = startIndex; i < childrenLength; ++i) { | 337 current = current.traverseNextNode(false, null, false); |
| 341 var child = children[i]; | |
| 342 | |
| 343 if (matchesQuery(child)) { | |
| 344 if (child._dataGridNode) { | |
| 345 // The child has a data grid node already, no need to re
member the ancestors. | |
| 346 this._searchResults.push({ profileNode: child }); | |
| 347 } else { | |
| 348 var ancestorsCopy = [].concat(ancestors); | |
| 349 ancestorsCopy.push(current); | |
| 350 this._searchResults.push({ profileNode: child, ancestors
: ancestorsCopy }); | |
| 351 } | |
| 352 } | |
| 353 | |
| 354 if (child.children.length) { | |
| 355 ancestors.push(current); | |
| 356 nextIndexes.push(i + 1); | |
| 357 current = child; | |
| 358 startIndex = 0; | |
| 359 break; | |
| 360 } | |
| 361 | |
| 362 if (i === (childrenLength - 1)) { | |
| 363 current = ancestors.pop(); | |
| 364 startIndex = nextIndexes.pop(); | |
| 365 } | |
| 366 } | |
| 367 } | 338 } |
| 368 | 339 |
| 369 finishedCallback(this, this._searchResults.length); | 340 finishedCallback(this, this._searchResults.length); |
| 370 }, | 341 }, |
| 371 | 342 |
| 372 jumpToFirstSearchResult: function() | 343 jumpToFirstSearchResult: function() |
| 373 { | 344 { |
| 374 if (!this._searchResults || !this._searchResults.length) | 345 if (!this._searchResults || !this._searchResults.length) |
| 375 return; | 346 return; |
| 376 this._currentSearchResultIndex = 0; | 347 this._currentSearchResultIndex = 0; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 { | 383 { |
| 413 return (this._searchResults && this._currentSearchResultIndex === (this.
_searchResults.length - 1)); | 384 return (this._searchResults && this._currentSearchResultIndex === (this.
_searchResults.length - 1)); |
| 414 }, | 385 }, |
| 415 | 386 |
| 416 _jumpToSearchResult: function(index) | 387 _jumpToSearchResult: function(index) |
| 417 { | 388 { |
| 418 var searchResult = this._searchResults[index]; | 389 var searchResult = this._searchResults[index]; |
| 419 if (!searchResult) | 390 if (!searchResult) |
| 420 return; | 391 return; |
| 421 | 392 |
| 422 var profileNode = this._searchResults[index].profileNode; | 393 var profileNode = searchResult.profileNode; |
| 423 if (!profileNode._dataGridNode && searchResult.ancestors) { | 394 profileNode.reveal(); |
| 424 var ancestors = searchResult.ancestors; | 395 profileNode.select(); |
| 425 for (var i = 0; i < ancestors.length; ++i) { | |
| 426 var ancestorProfileNode = ancestors[i]; | |
| 427 var gridNode = ancestorProfileNode._dataGridNode; | |
| 428 if (gridNode) | |
| 429 gridNode.expand(); | |
| 430 } | |
| 431 | |
| 432 // No need to keep the ancestors around. | |
| 433 delete searchResult.ancestors; | |
| 434 } | |
| 435 | |
| 436 gridNode = profileNode._dataGridNode; | |
| 437 if (!gridNode) | |
| 438 return; | |
| 439 | |
| 440 gridNode.reveal(); | |
| 441 gridNode.select(); | |
| 442 }, | 396 }, |
| 443 | 397 |
| 444 _changeView: function(event) | 398 _changeView: function(event) |
| 445 { | 399 { |
| 446 if (!event || !this.profile) | 400 if (!event || !this.profile) |
| 447 return; | 401 return; |
| 448 | 402 |
| 449 if (event.target.selectedIndex == 1 && this.view == "Heavy") { | 403 if (event.target.selectedIndex == 1 && this.view == "Heavy") { |
| 450 this.profileDataGridTree = this.topDownProfileDataGridTree; | 404 this.profileDataGridTree = this.topDownProfileDataGridTree; |
| 451 this._sortProfile(); | 405 this._sortProfile(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 472 this.showSelfTimeAsPercent = !currentState; | 426 this.showSelfTimeAsPercent = !currentState; |
| 473 this.showTotalTimeAsPercent = !currentState; | 427 this.showTotalTimeAsPercent = !currentState; |
| 474 this.showAverageTimeAsPercent = !currentState; | 428 this.showAverageTimeAsPercent = !currentState; |
| 475 this.refreshShowAsPercents(); | 429 this.refreshShowAsPercents(); |
| 476 }, | 430 }, |
| 477 | 431 |
| 478 _updatePercentButton: function() | 432 _updatePercentButton: function() |
| 479 { | 433 { |
| 480 if (this.showSelfTimeAsPercent && this.showTotalTimeAsPercent && this.sh
owAverageTimeAsPercent) { | 434 if (this.showSelfTimeAsPercent && this.showTotalTimeAsPercent && this.sh
owAverageTimeAsPercent) { |
| 481 this.percentButton.title = WebInspector.UIString("Show absolute tota
l and self times."); | 435 this.percentButton.title = WebInspector.UIString("Show absolute tota
l and self times."); |
| 482 this.percentButton.addStyleClass("toggled-on"); | 436 this.percentButton.toggled = true; |
| 483 } else { | 437 } else { |
| 484 this.percentButton.title = WebInspector.UIString("Show total and sel
f times as percentages."); | 438 this.percentButton.title = WebInspector.UIString("Show total and sel
f times as percentages."); |
| 485 this.percentButton.removeStyleClass("toggled-on"); | 439 this.percentButton.toggled = false; |
| 486 } | 440 } |
| 487 }, | 441 }, |
| 488 | 442 |
| 489 _focusClicked: function(event) | 443 _focusClicked: function(event) |
| 490 { | 444 { |
| 491 if (!this.dataGrid.selectedNode) | 445 if (!this.dataGrid.selectedNode) |
| 492 return; | 446 return; |
| 493 | 447 |
| 494 this.resetButton.removeStyleClass("hidden"); | 448 this.resetButton.visible = true; |
| 495 this.profileDataGridTree.focus(this.dataGrid.selectedNode); | 449 this.profileDataGridTree.focus(this.dataGrid.selectedNode); |
| 496 this.refresh(); | 450 this.refresh(); |
| 497 this.refreshVisibleData(); | 451 this.refreshVisibleData(); |
| 498 }, | 452 }, |
| 499 | 453 |
| 500 _excludeClicked: function(event) | 454 _excludeClicked: function(event) |
| 501 { | 455 { |
| 502 var selectedNode = this.dataGrid.selectedNode | 456 var selectedNode = this.dataGrid.selectedNode |
| 503 | 457 |
| 504 if (!selectedNode) | 458 if (!selectedNode) |
| 505 return; | 459 return; |
| 506 | 460 |
| 507 selectedNode.deselect(); | 461 selectedNode.deselect(); |
| 508 | 462 |
| 509 this.resetButton.removeStyleClass("hidden"); | 463 this.resetButton.visible = true; |
| 510 this.profileDataGridTree.exclude(selectedNode); | 464 this.profileDataGridTree.exclude(selectedNode); |
| 511 this.refresh(); | 465 this.refresh(); |
| 512 this.refreshVisibleData(); | 466 this.refreshVisibleData(); |
| 513 }, | 467 }, |
| 514 | 468 |
| 515 _resetClicked: function(event) | 469 _resetClicked: function(event) |
| 516 { | 470 { |
| 517 this.resetButton.addStyleClass("hidden"); | 471 this.resetButton.visible = false; |
| 518 this.profileDataGridTree.restore(); | 472 this.profileDataGridTree.restore(); |
| 519 this.refresh(); | 473 this.refresh(); |
| 520 this.refreshVisibleData(); | 474 this.refreshVisibleData(); |
| 521 }, | 475 }, |
| 522 | 476 |
| 523 _dataGridNodeSelected: function(node) | 477 _dataGridNodeSelected: function(node) |
| 524 { | 478 { |
| 525 this.focusButton.disabled = false; | 479 this.focusButton.disabled = false; |
| 526 this.excludeButton.disabled = false; | 480 this.excludeButton.disabled = false; |
| 527 }, | 481 }, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 this.showAverageTimeAsPercent = !this.showAverageTimeAsPercent; | 525 this.showAverageTimeAsPercent = !this.showAverageTimeAsPercent; |
| 572 | 526 |
| 573 this.refreshShowAsPercents(); | 527 this.refreshShowAsPercents(); |
| 574 | 528 |
| 575 event.preventDefault(); | 529 event.preventDefault(); |
| 576 event.stopPropagation(); | 530 event.stopPropagation(); |
| 577 } | 531 } |
| 578 } | 532 } |
| 579 | 533 |
| 580 WebInspector.ProfileView.prototype.__proto__ = WebInspector.View.prototype; | 534 WebInspector.ProfileView.prototype.__proto__ = WebInspector.View.prototype; |
| OLD | NEW |