1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26WebInspector.DebuggerSidebarPanel = function() 27{ 28 WebInspector.NavigationSidebarPanel.call(this, "debugger", WebInspector.UIString("Debugger"), "Images/NavigationItemBug.svg", "3", true); 29 30 WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceChanged, this); 31 WebInspector.Frame.addEventListener(WebInspector.Frame.Event.ResourceWasAdded, this._resourceAdded, this); 32 33 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointsEnabledDidChange, this._breakpointsEnabledDidChange, this); 34 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.CallFramesDidChange, this._debuggerCallFramesDidChange, this); 35 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointAdded, this._breakpointAdded, this); 36 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointRemoved, this._breakpointRemoved, this); 37 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptAdded, this._scriptAdded, this); 38 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ScriptsCleared, this._scriptsCleared, this); 39 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, this._debuggerDidPause, this); 40 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, this._debuggerDidResume, this); 41 WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.ActiveCallFrameDidChange, this._debuggerActiveCallFrameDidChange, this); 42 43 this.pauseOrResumeKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.Control | WebInspector.KeyboardShortcut.Modifier.CommandOrControl, "Y", this._debuggerPauseResumeButtonClicked.bind(this)); 44 this._stepOverKeyboardShortcut = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.F6, this._debuggerStepOverButtonClicked.bind(this)); 45 this._stepIntoKeyboardShortcut = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.F7, this._debuggerStepIntoButtonClicked.bind(this)); 46 this._stepOutKeyboardShortcut = new WebInspector.KeyboardShortcut(null, WebInspector.KeyboardShortcut.Key.F8, this._debuggerStepOutButtonClicked.bind(this)); 47 48 this.pauseOrResumeAlternateKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl, WebInspector.KeyboardShortcut.Key.Backslash, this._debuggerPauseResumeButtonClicked.bind(this)); 49 this._stepOverAlternateKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl, WebInspector.KeyboardShortcut.Key.SingleQuote, this._debuggerStepOverButtonClicked.bind(this)); 50 this._stepIntoAlternateKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.CommandOrControl, WebInspector.KeyboardShortcut.Key.Semicolon, this._debuggerStepIntoButtonClicked.bind(this)); 51 this._stepOutAlternateKeyboardShortcut = new WebInspector.KeyboardShortcut(WebInspector.KeyboardShortcut.Modifier.Shift | WebInspector.KeyboardShortcut.Modifier.CommandOrControl, WebInspector.KeyboardShortcut.Key.Semicolon, this._debuggerStepOutButtonClicked.bind(this)); 52 53 this._navigationBar = new WebInspector.NavigationBar; 54 this.element.appendChild(this._navigationBar.element); 55 56 var breakpointsImage, pauseImage, resumeImage, stepOverImage, stepIntoImage, stepOutImage; 57 if (WebInspector.Platform.isLegacyMacOS) { 58 breakpointsImage = {src: "Images/Legacy/Breakpoints.svg", width: 16, height: 16}; 59 pauseImage = {src: "Images/Legacy/Pause.svg", width: 16, height: 16}; 60 resumeImage = {src: "Images/Legacy/Resume.svg", width: 16, height: 16}; 61 stepOverImage = {src: "Images/Legacy/StepOver.svg", width: 16, height: 16}; 62 stepIntoImage = {src: "Images/Legacy/StepInto.svg", width: 16, height: 16}; 63 stepOutImage = {src: "Images/Legacy/StepOut.svg", width: 16, height: 16}; 64 } else { 65 breakpointsImage = {src: "Images/Breakpoints.svg", width: 15, height: 15}; 66 pauseImage = {src: "Images/Pause.svg", width: 15, height: 15}; 67 resumeImage = {src: "Images/Resume.svg", width: 15, height: 15}; 68 stepOverImage = {src: "Images/StepOver.svg", width: 15, height: 15}; 69 stepIntoImage = {src: "Images/StepInto.svg", width: 15, height: 15}; 70 stepOutImage = {src: "Images/StepOut.svg", width: 15, height: 15}; 71 } 72 73 var toolTip = WebInspector.UIString("Enable all breakpoints"); 74 var altToolTip = WebInspector.UIString("Disable all breakpoints"); 75 76 this._debuggerBreakpointsButtonItem = new WebInspector.ActivateButtonNavigationItem("debugger-breakpoints", toolTip, altToolTip, breakpointsImage.src, breakpointsImage.width, breakpointsImage.height); 77 this._debuggerBreakpointsButtonItem.activated = WebInspector.debuggerManager.breakpointsEnabled; 78 this._debuggerBreakpointsButtonItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._breakpointsToggleButtonClicked, this); 79 this._navigationBar.addNavigationItem(this._debuggerBreakpointsButtonItem); 80 81 toolTip = WebInspector.UIString("Pause script execution (%s or %s)").format(this.pauseOrResumeKeyboardShortcut.displayName, this.pauseOrResumeAlternateKeyboardShortcut.displayName); 82 altToolTip = WebInspector.UIString("Continue script execution (%s or %s)").format(this.pauseOrResumeKeyboardShortcut.displayName, this.pauseOrResumeAlternateKeyboardShortcut.displayName); 83 84 this._debuggerPauseResumeButtonItem = new WebInspector.ToggleButtonNavigationItem("debugger-pause-resume", toolTip, altToolTip, pauseImage.src, resumeImage.src, pauseImage.width, pauseImage.height); 85 this._debuggerPauseResumeButtonItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._debuggerPauseResumeButtonClicked, this); 86 this._navigationBar.addNavigationItem(this._debuggerPauseResumeButtonItem); 87 88 this._debuggerStepOverButtonItem = new WebInspector.ButtonNavigationItem("debugger-step-over", WebInspector.UIString("Step over (%s or %s)").format(this._stepOverKeyboardShortcut.displayName, this._stepOverAlternateKeyboardShortcut.displayName), stepOverImage.src, stepOverImage.width, stepOverImage.height); 89 this._debuggerStepOverButtonItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._debuggerStepOverButtonClicked, this); 90 this._debuggerStepOverButtonItem.enabled = false; 91 this._navigationBar.addNavigationItem(this._debuggerStepOverButtonItem); 92 93 this._debuggerStepIntoButtonItem = new WebInspector.ButtonNavigationItem("debugger-step-into", WebInspector.UIString("Step into (%s or %s)").format(this._stepIntoKeyboardShortcut.displayName, this._stepIntoAlternateKeyboardShortcut.displayName), stepIntoImage.src, stepIntoImage.width, stepIntoImage.height); 94 this._debuggerStepIntoButtonItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._debuggerStepIntoButtonClicked, this); 95 this._debuggerStepIntoButtonItem.enabled = false; 96 this._navigationBar.addNavigationItem(this._debuggerStepIntoButtonItem); 97 98 this._debuggerStepOutButtonItem = new WebInspector.ButtonNavigationItem("debugger-step-out", WebInspector.UIString("Step out (%s or %s)").format(this._stepOutKeyboardShortcut.displayName, this._stepOutAlternateKeyboardShortcut.displayName), stepOutImage.src, stepOutImage.width, stepOutImage.height); 99 this._debuggerStepOutButtonItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._debuggerStepOutButtonClicked, this); 100 this._debuggerStepOutButtonItem.enabled = false; 101 this._navigationBar.addNavigationItem(this._debuggerStepOutButtonItem); 102 103 // Add this offset-sections class name so the sticky headers don't overlap the navigation bar. 104 this.element.classList.add(WebInspector.DebuggerSidebarPanel.OffsetSectionsStyleClassName); 105 106 this._allExceptionsBreakpointTreeElement = new WebInspector.BreakpointTreeElement(WebInspector.debuggerManager.allExceptionsBreakpoint, WebInspector.DebuggerSidebarPanel.ExceptionIconStyleClassName, WebInspector.UIString("All Exceptions")); 107 this._allUncaughtExceptionsBreakpointTreeElement = new WebInspector.BreakpointTreeElement(WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint, WebInspector.DebuggerSidebarPanel.ExceptionIconStyleClassName, WebInspector.UIString("All Uncaught Exceptions")); 108 109 this.filterBar.placeholder = WebInspector.UIString("Filter Breakpoint List"); 110 111 this._breakpointsContentTreeOutline = this.contentTreeOutline; 112 this._breakpointsContentTreeOutline.onselect = this._treeElementSelected.bind(this); 113 this._breakpointsContentTreeOutline.ondelete = this._breakpointTreeOutlineDeleteTreeElement.bind(this); 114 this._breakpointsContentTreeOutline.oncontextmenu = this._breakpointTreeOutlineContextMenuTreeElement.bind(this); 115 116 this._breakpointsContentTreeOutline.appendChild(this._allExceptionsBreakpointTreeElement); 117 this._breakpointsContentTreeOutline.appendChild(this._allUncaughtExceptionsBreakpointTreeElement); 118 119 var breakpointsRow = new WebInspector.DetailsSectionRow; 120 breakpointsRow.element.appendChild(this._breakpointsContentTreeOutline.element); 121 122 var breakpointsGroup = new WebInspector.DetailsSectionGroup([breakpointsRow]); 123 var breakpointsSection = new WebInspector.DetailsSection("breakpoints", WebInspector.UIString("Breakpoints"), [breakpointsGroup]); 124 this.contentElement.appendChild(breakpointsSection.element); 125 126 this._callStackContentTreeOutline = this.createContentTreeOutline(true); 127 this._callStackContentTreeOutline.onselect = this._treeElementSelected.bind(this); 128 129 this._callStackRow = new WebInspector.DetailsSectionRow(WebInspector.UIString("No Call Frames")); 130 this._callStackRow.showEmptyMessage(); 131 132 var callStackGroup = new WebInspector.DetailsSectionGroup([this._callStackRow]); 133 this._callStackSection = new WebInspector.DetailsSection("call-stack", WebInspector.UIString("Call Stack"), [callStackGroup]); 134 135 WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.DisplayLocationDidChange, this._breakpointDisplayLocationDidChange, this); 136}; 137 138WebInspector.DebuggerSidebarPanel.OffsetSectionsStyleClassName = "offset-sections"; 139WebInspector.DebuggerSidebarPanel.ExceptionIconStyleClassName = "breakpoint-exception-icon"; 140 141WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey = "debugger-sidebar-panel-all-exceptions-breakpoint"; 142WebInspector.DebuggerSidebarPanel.SelectedAllUncaughtExceptionsCookieKey = "debugger-sidebar-panel-all-uncaught-exceptions-breakpoint"; 143 144WebInspector.DebuggerSidebarPanel.prototype = { 145 constructor: WebInspector.DebuggerSidebarPanel, 146 147 // Public 148 149 get hasSelectedElement() 150 { 151 return !!this._breakpointsContentTreeOutline.selectedTreeElement || !!this._callStackContentTreeOutline.selectedTreeElement; 152 }, 153 154 showDefaultContentView: function() 155 { 156 WebInspector.resourceSidebarPanel.showDefaultContentView(); 157 }, 158 159 treeElementForRepresentedObject: function(representedObject) 160 { 161 // The main resource is used as the representedObject instead of Frame in our tree. 162 if (representedObject instanceof WebInspector.Frame) 163 representedObject = representedObject.mainResource; 164 165 return this.contentTreeOutline.getCachedTreeElement(representedObject); 166 }, 167 168 // Protected 169 170 saveStateToCookie: function(cookie) 171 { 172 console.assert(cookie); 173 174 var selectedTreeElement = this._breakpointsContentTreeOutline.selectedTreeElement; 175 if (!selectedTreeElement) 176 return; 177 178 var representedObject = selectedTreeElement.representedObject; 179 180 if (representedObject === WebInspector.debuggerManager.allExceptionsBreakpoint) 181 cookie[WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey] = true; 182 183 if (representedObject === WebInspector.debuggerManager.allUncaughtExceptionsBreakpoint) 184 cookie[WebInspector.DebuggerSidebarPanel.SelectedAllUncaughtExceptionsCookieKey] = true; 185 186 WebInspector.NavigationSidebarPanel.prototype.saveStateToCookie.call(this, cookie); 187 }, 188 189 restoreStateFromCookie: function(cookie, relaxedMatchDelay) 190 { 191 console.assert(cookie); 192 193 // Eagerly resolve the special breakpoints; otherwise, use the default behavior. 194 if (cookie[WebInspector.DebuggerSidebarPanel.SelectedAllExceptionsCookieKey]) 195 this._allExceptionsBreakpointTreeElement.revealAndSelect(); 196 else if (cookie[WebInspector.DebuggerSidebarPanel.SelectedAllUncaughtExceptionsCookieKey]) 197 this._allUncaughtExceptionsBreakpointTreeElement.revealAndSelect(); 198 else 199 WebInspector.NavigationSidebarPanel.prototype.restoreStateFromCookie.call(this, cookie, relaxedMatchDelay); 200 }, 201 202 // Private 203 204 _debuggerPauseResumeButtonClicked: function(event) 205 { 206 if (WebInspector.debuggerManager.paused) 207 WebInspector.debuggerManager.resume(); 208 else { 209 this._debuggerPauseResumeButtonItem.enabled = false; 210 WebInspector.debuggerManager.pause(); 211 } 212 }, 213 214 _debuggerStepOverButtonClicked: function(event) 215 { 216 WebInspector.debuggerManager.stepOver(); 217 }, 218 219 _debuggerStepIntoButtonClicked: function(event) 220 { 221 WebInspector.debuggerManager.stepInto(); 222 }, 223 224 _debuggerStepOutButtonClicked: function(event) 225 { 226 WebInspector.debuggerManager.stepOut(); 227 }, 228 229 _debuggerDidPause: function(event) 230 { 231 this.contentElement.insertBefore(this._callStackSection.element, this.contentElement.firstChild); 232 233 this._debuggerPauseResumeButtonItem.enabled = true; 234 this._debuggerPauseResumeButtonItem.toggled = true; 235 this._debuggerStepOverButtonItem.enabled = true; 236 this._debuggerStepIntoButtonItem.enabled = true; 237 }, 238 239 _debuggerDidResume: function(event) 240 { 241 this._callStackSection.element.remove(); 242 243 this._debuggerPauseResumeButtonItem.enabled = true; 244 this._debuggerPauseResumeButtonItem.toggled = false; 245 this._debuggerStepOverButtonItem.enabled = false; 246 this._debuggerStepIntoButtonItem.enabled = false; 247 this._debuggerStepOutButtonItem.enabled = false; 248 }, 249 250 _breakpointsEnabledDidChange: function(event) 251 { 252 this._debuggerBreakpointsButtonItem.activated = WebInspector.debuggerManager.breakpointsEnabled; 253 }, 254 255 _breakpointsToggleButtonClicked: function(event) 256 { 257 WebInspector.debuggerManager.breakpointsEnabled = !this._debuggerBreakpointsButtonItem.activated; 258 }, 259 260 _addBreakpoint: function(breakpoint, sourceCode) 261 { 262 var sourceCode = breakpoint.sourceCodeLocation.displaySourceCode; 263 if (!sourceCode) 264 return null; 265 266 var parentTreeElement = this._breakpointsContentTreeOutline.getCachedTreeElement(sourceCode); 267 if (!parentTreeElement) { 268 if (sourceCode instanceof WebInspector.SourceMapResource) 269 parentTreeElement = new WebInspector.SourceMapResourceTreeElement(sourceCode); 270 else if (sourceCode instanceof WebInspector.Resource) 271 parentTreeElement = new WebInspector.ResourceTreeElement(sourceCode); 272 else if (sourceCode instanceof WebInspector.Script) 273 parentTreeElement = new WebInspector.ScriptTreeElement(sourceCode); 274 } 275 276 if (!parentTreeElement.parent) { 277 parentTreeElement.hasChildren = true; 278 parentTreeElement.expand(); 279 280 this._breakpointsContentTreeOutline.insertChild(parentTreeElement, insertionIndexForObjectInListSortedByFunction(parentTreeElement, this._breakpointsContentTreeOutline.children, this._compareTopLevelTreeElements.bind(this))); 281 } 282 283 // Mark disabled breakpoints as resolved if there is source code loaded with that URL. 284 // This gives the illusion the breakpoint was resolved, but since we don't send disabled 285 // breakpoints to the backend we don't know for sure. If the user enables the breakpoint 286 // it will be resolved properly. 287 if (breakpoint.disabled) 288 breakpoint.resolved = true; 289 290 var breakpointTreeElement = new WebInspector.BreakpointTreeElement(breakpoint); 291 parentTreeElement.insertChild(breakpointTreeElement, insertionIndexForObjectInListSortedByFunction(breakpointTreeElement, parentTreeElement.children, this._compareBreakpointTreeElements)); 292 return breakpointTreeElement; 293 }, 294 295 _addBreakpointsForSourceCode: function(sourceCode) 296 { 297 var breakpoints = WebInspector.debuggerManager.breakpointsForSourceCode(sourceCode); 298 for (var i = 0; i < breakpoints.length; ++i) 299 this._addBreakpoint(breakpoints[i], sourceCode); 300 }, 301 302 _resourceAdded: function(event) 303 { 304 var resource = event.data.resource; 305 this._addBreakpointsForSourceCode(resource); 306 }, 307 308 _mainResourceChanged: function(event) 309 { 310 var resource = event.target.mainResource; 311 this._addBreakpointsForSourceCode(resource); 312 }, 313 314 _scriptAdded: function(event) 315 { 316 var script = event.data.script; 317 318 // Don't add breakpoints if the script is represented by a Resource. They were 319 // already added by _resourceAdded. 320 if (script.resource) 321 return; 322 323 this._addBreakpointsForSourceCode(script); 324 }, 325 326 _scriptsCleared: function(event) 327 { 328 for (var i = this._breakpointsContentTreeOutline.children.length - 1; i >= 0; --i) { 329 var treeElement = this._breakpointsContentTreeOutline.children[i]; 330 if (!(treeElement instanceof WebInspector.ScriptTreeElement)) 331 continue; 332 333 this._breakpointsContentTreeOutline.removeChildAtIndex(i, true, true); 334 } 335 }, 336 337 _breakpointAdded: function(event) 338 { 339 var breakpoint = event.data.breakpoint; 340 this._addBreakpoint(breakpoint); 341 }, 342 343 _breakpointRemoved: function(event) 344 { 345 var breakpoint = event.data.breakpoint; 346 347 var breakpointTreeElement = this._breakpointsContentTreeOutline.getCachedTreeElement(breakpoint); 348 console.assert(breakpointTreeElement); 349 if (!breakpointTreeElement) 350 return; 351 352 this._removeBreakpointTreeElement(breakpointTreeElement); 353 }, 354 355 _breakpointDisplayLocationDidChange: function(event) 356 { 357 var breakpoint = event.target; 358 if (event.data.oldDisplaySourceCode === breakpoint.displaySourceCode) 359 return; 360 361 var breakpointTreeElement = this._breakpointsContentTreeOutline.getCachedTreeElement(breakpoint); 362 if (!breakpointTreeElement) 363 return; 364 365 // A known breakpoint moved between resources, remove the old tree element 366 // and create a new tree element with the updated file. 367 368 var wasSelected = breakpointTreeElement.selected; 369 370 this._removeBreakpointTreeElement(breakpointTreeElement); 371 var newBreakpointTreeElement = this._addBreakpoint(breakpoint); 372 373 if (newBreakpointTreeElement && wasSelected) 374 newBreakpointTreeElement.revealAndSelect(true, false, true, true); 375 }, 376 377 _removeBreakpointTreeElement: function(breakpointTreeElement) 378 { 379 var parentTreeElement = breakpointTreeElement.parent; 380 parentTreeElement.removeChild(breakpointTreeElement); 381 382 console.assert(parentTreeElement.parent === this._breakpointsContentTreeOutline); 383 384 if (!parentTreeElement.children.length) 385 this._breakpointsContentTreeOutline.removeChild(parentTreeElement); 386 }, 387 388 _debuggerCallFramesDidChange: function() 389 { 390 this._callStackContentTreeOutline.removeChildren(); 391 392 var callFrames = WebInspector.debuggerManager.callFrames; 393 if (!callFrames || !callFrames.length) { 394 this._callStackRow.showEmptyMessage(); 395 return; 396 } 397 398 this._callStackRow.hideEmptyMessage(); 399 this._callStackRow.element.appendChild(this._callStackContentTreeOutline.element); 400 401 var treeElementToSelect = null; 402 403 var activeCallFrame = WebInspector.debuggerManager.activeCallFrame; 404 for (var i = 0; i < callFrames.length; ++i) { 405 var callFrameTreeElement = new WebInspector.CallFrameTreeElement(callFrames[i]); 406 if (callFrames[i] === activeCallFrame) 407 treeElementToSelect = callFrameTreeElement; 408 this._callStackContentTreeOutline.appendChild(callFrameTreeElement); 409 } 410 411 if (treeElementToSelect) 412 treeElementToSelect.select(true, true); 413 }, 414 415 _debuggerActiveCallFrameDidChange: function() 416 { 417 var callFrames = WebInspector.debuggerManager.callFrames; 418 if (!callFrames) 419 return; 420 421 var indexOfActiveCallFrame = callFrames.indexOf(WebInspector.debuggerManager.activeCallFrame); 422 // It is useful to turn off the step out button when there is no call frame to go through 423 // since there might be call frames in the backend that were removed when processing the call 424 // frame payload. 425 this._debuggerStepOutButtonItem.enabled = indexOfActiveCallFrame < callFrames.length - 1; 426 }, 427 428 _breakpointsBeneathTreeElement: function(treeElement) 429 { 430 console.assert(treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement); 431 if (!(treeElement instanceof WebInspector.ResourceTreeElement) && !(treeElement instanceof WebInspector.ScriptTreeElement)) 432 return []; 433 434 var breakpoints = []; 435 var breakpointTreeElements = treeElement.children; 436 for (var i = 0; i < breakpointTreeElements.length; ++i) { 437 console.assert(breakpointTreeElements[i] instanceof WebInspector.BreakpointTreeElement); 438 console.assert(breakpointTreeElements[i].breakpoint); 439 var breakpoint = breakpointTreeElements[i].breakpoint; 440 if (breakpoint) 441 breakpoints.push(breakpoint); 442 } 443 444 return breakpoints; 445 }, 446 447 _removeAllBreakpoints: function(breakpoints) 448 { 449 for (var i = 0; i < breakpoints.length; ++i) { 450 var breakpoint = breakpoints[i]; 451 if (WebInspector.debuggerManager.isBreakpointRemovable(breakpoint)) 452 WebInspector.debuggerManager.removeBreakpoint(breakpoint); 453 } 454 }, 455 456 _toggleAllBreakpoints: function(breakpoints, disabled) 457 { 458 for (var i = 0; i < breakpoints.length; ++i) 459 breakpoints[i].disabled = disabled; 460 }, 461 462 _breakpointTreeOutlineDeleteTreeElement: function(treeElement) 463 { 464 console.assert(treeElement.selected); 465 console.assert(treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement); 466 if (!(treeElement instanceof WebInspector.ResourceTreeElement) && !(treeElement instanceof WebInspector.ScriptTreeElement)) 467 return false; 468 469 var wasTopResourceTreeElement = treeElement.previousSibling === this._allUncaughtExceptionsBreakpointTreeElement; 470 var nextSibling = treeElement.nextSibling; 471 472 var breakpoints = this._breakpointsBeneathTreeElement(treeElement); 473 this._removeAllBreakpoints(breakpoints); 474 475 if (wasTopResourceTreeElement && nextSibling) 476 nextSibling.select(true, true); 477 478 return true; 479 }, 480 481 _breakpointTreeOutlineContextMenuTreeElement: function(event, treeElement) 482 { 483 console.assert(treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement); 484 if (!(treeElement instanceof WebInspector.ResourceTreeElement) && !(treeElement instanceof WebInspector.ScriptTreeElement)) 485 return; 486 487 var breakpoints = this._breakpointsBeneathTreeElement(treeElement); 488 var shouldDisable = false; 489 for (var i = 0; i < breakpoints.length; ++i) { 490 if (!breakpoints[i].disabled) { 491 shouldDisable = true; 492 break; 493 } 494 } 495 496 function removeAllResourceBreakpoints() 497 { 498 this._removeAllBreakpoints(breakpoints); 499 } 500 501 function toggleAllResourceBreakpoints() 502 { 503 this._toggleAllBreakpoints(breakpoints, shouldDisable); 504 } 505 506 var contextMenu = new WebInspector.ContextMenu(event); 507 if (shouldDisable) 508 contextMenu.appendItem(WebInspector.UIString("Disable Breakpoints"), toggleAllResourceBreakpoints.bind(this)); 509 else 510 contextMenu.appendItem(WebInspector.UIString("Enable Breakpoints"), toggleAllResourceBreakpoints.bind(this)); 511 contextMenu.appendItem(WebInspector.UIString("Delete Breakpoints"), removeAllResourceBreakpoints.bind(this)); 512 contextMenu.show(); 513 }, 514 515 _treeElementSelected: function(treeElement, selectedByUser) 516 { 517 function deselectCallStackContentTreeElements() 518 { 519 // Deselect any tree element in the call stack content tree outline to prevent two selections in the sidebar. 520 var selectedTreeElement = this._callStackContentTreeOutline.selectedTreeElement; 521 if (selectedTreeElement) 522 selectedTreeElement.deselect(); 523 } 524 525 if (treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement) { 526 // If the resource is being selected when it has no children it is in the process of being deleted, don't do anything. 527 if (!treeElement.children.length) 528 return; 529 deselectCallStackContentTreeElements.call(this); 530 WebInspector.resourceSidebarPanel.showSourceCode(treeElement.representedObject); 531 return; 532 } 533 534 if (treeElement instanceof WebInspector.CallFrameTreeElement) { 535 // Deselect any tree element in the breakpoints content tree outline to prevent two selections in the sidebar. 536 var selectedTreeElement = this._breakpointsContentTreeOutline.selectedTreeElement; 537 if (selectedTreeElement) 538 selectedTreeElement.deselect(); 539 540 var callFrame = treeElement.callFrame; 541 WebInspector.debuggerManager.activeCallFrame = callFrame; 542 WebInspector.resourceSidebarPanel.showSourceCodeLocation(callFrame.sourceCodeLocation); 543 return; 544 } 545 546 if (!(treeElement instanceof WebInspector.BreakpointTreeElement)) 547 return; 548 549 deselectCallStackContentTreeElements.call(this); 550 551 if (!treeElement.parent.representedObject) 552 return; 553 554 console.assert(treeElement.parent.representedObject instanceof WebInspector.SourceCode); 555 if (!(treeElement.parent.representedObject instanceof WebInspector.SourceCode)) 556 return; 557 558 var breakpoint = treeElement.breakpoint; 559 WebInspector.resourceSidebarPanel.showSourceCodeLocation(breakpoint.sourceCodeLocation); 560 }, 561 562 _compareTopLevelTreeElements: function(a, b) 563 { 564 if (a === this._allExceptionsBreakpointTreeElement) 565 return -1; 566 if (b === this._allExceptionsBreakpointTreeElement) 567 return 1; 568 569 if (a === this._allUncaughtExceptionsBreakpointTreeElement) 570 return -1; 571 if (b === this._allUncaughtExceptionsBreakpointTreeElement) 572 return 1; 573 574 return a.mainTitle.localeCompare(b.mainTitle); 575 }, 576 577 _compareBreakpointTreeElements: function(a, b) 578 { 579 var aLocation = a.breakpoint.sourceCodeLocation; 580 var bLocation = b.breakpoint.sourceCodeLocation; 581 582 var comparisonResult = aLocation.displayLineNumber - bLocation.displayLineNumber; 583 if (comparisonResult !== 0) 584 return comparisonResult; 585 586 return aLocation.displayColumnNumber - bLocation.displayColumnNumber; 587 } 588}; 589 590WebInspector.DebuggerSidebarPanel.prototype.__proto__ = WebInspector.NavigationSidebarPanel.prototype; 591