Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / CallStackSidebarPane.js
1 /*
2  * Copyright (C) 2008 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 /**
27  * @constructor
28  * @extends {WebInspector.SidebarPane}
29  */
30 WebInspector.CallStackSidebarPane = function()
31 {
32     WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack"));
33     this.bodyElement.addEventListener("keydown", this._keyDown.bind(this), true);
34     this.bodyElement.tabIndex = 0;
35
36     var asyncCheckbox = this.titleElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Async"), WebInspector.settings.enableAsyncStackTraces, true, undefined, WebInspector.UIString("Capture async stack traces")));
37     asyncCheckbox.classList.add("scripts-callstack-async");
38     asyncCheckbox.addEventListener("click", consumeEvent, false);
39     WebInspector.settings.enableAsyncStackTraces.addChangeListener(this._asyncStackTracesStateChanged, this);
40 }
41
42 WebInspector.CallStackSidebarPane.Events = {
43     CallFrameRestarted: "CallFrameRestarted",
44     CallFrameSelected: "CallFrameSelected"
45 }
46
47 WebInspector.CallStackSidebarPane.prototype = {
48     /**
49      * @param {?Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames
50      * @param {?WebInspector.DebuggerModel.StackTrace} asyncStackTrace
51      */
52     update: function(callFrames, asyncStackTrace)
53     {
54         this.bodyElement.removeChildren();
55         delete this._statusMessageElement;
56         /** @type {!Array.<!WebInspector.CallStackSidebarPane.Placard>} */
57         this.placards = [];
58
59         if (!callFrames) {
60             var infoElement = this.bodyElement.createChild("div", "info");
61             infoElement.textContent = WebInspector.UIString("Not Paused");
62             return;
63         }
64
65         this._appendSidebarPlacards(callFrames);
66
67         while (asyncStackTrace) {
68             var title = asyncStackTrace.description;
69             if (title)
70                 title += " " + WebInspector.UIString("(async)");
71             else
72                 title = WebInspector.UIString("Async Call");
73             var asyncPlacard = new WebInspector.Placard(title, "");
74             asyncPlacard.element.classList.add("placard-label");
75             this.bodyElement.appendChild(asyncPlacard.element);
76             this._appendSidebarPlacards(asyncStackTrace.callFrames, asyncPlacard);
77             asyncStackTrace = asyncStackTrace.asyncStackTrace;
78         }
79     },
80
81     /**
82      * @param {!Array.<!WebInspector.DebuggerModel.CallFrame>} callFrames
83      * @param {!WebInspector.Placard=} asyncPlacard
84      */
85     _appendSidebarPlacards: function(callFrames, asyncPlacard)
86     {
87         for (var i = 0, n = callFrames.length; i < n; ++i) {
88             var placard = new WebInspector.CallStackSidebarPane.Placard(callFrames[i], asyncPlacard);
89             placard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
90             placard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true);
91             if (!i && asyncPlacard) {
92                 asyncPlacard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
93                 asyncPlacard.element.addEventListener("contextmenu", this._placardContextMenu.bind(this, placard), true);
94             }
95             this.placards.push(placard);
96             this.bodyElement.appendChild(placard.element);
97         }
98     },
99
100     /**
101      * @param {!WebInspector.CallStackSidebarPane.Placard} placard
102      */
103     _placardContextMenu: function(placard, event)
104     {
105         var contextMenu = new WebInspector.ContextMenu(event);
106
107         if (!placard._callFrame.isAsync())
108             contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Restart frame" : "Restart Frame"), this._restartFrame.bind(this, placard));
109
110         contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy stack trace" : "Copy Stack Trace"), this._copyStackTrace.bind(this));
111         contextMenu.show();
112     },
113
114     /**
115      * @param {!WebInspector.CallStackSidebarPane.Placard} placard
116      */
117     _restartFrame: function(placard)
118     {
119         placard._callFrame.restart();
120         this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameRestarted, placard._callFrame);
121     },
122
123     _asyncStackTracesStateChanged: function()
124     {
125         var enabled = WebInspector.settings.enableAsyncStackTraces.get();
126         if (!enabled && this.placards)
127             this._removeAsyncPlacards();
128     },
129
130     _removeAsyncPlacards: function()
131     {
132         var shouldSelectTopFrame = false;
133         var lastSyncPlacardIndex = -1;
134         for (var i = 0; i < this.placards.length; ++i) {
135             var placard = this.placards[i];
136             if (placard._asyncPlacard) {
137                 if (placard.selected)
138                     shouldSelectTopFrame = true;
139                 placard._asyncPlacard.element.remove();
140                 placard.element.remove();
141             } else {
142                 lastSyncPlacardIndex = i;
143             }
144         }
145         this.placards.length = lastSyncPlacardIndex + 1;
146         if (shouldSelectTopFrame)
147             this._selectPlacardByIndex(0);
148     },
149
150     /**
151      * @param {!WebInspector.DebuggerModel.CallFrame} x
152      */
153     setSelectedCallFrame: function(x)
154     {
155         for (var i = 0; i < this.placards.length; ++i) {
156             var placard = this.placards[i];
157             placard.selected = (placard._callFrame === x);
158         }
159     },
160
161     /**
162      * @return {boolean}
163      */
164     _selectNextCallFrameOnStack: function()
165     {
166         var index = this._selectedCallFrameIndex();
167         if (index === -1)
168             return false;
169         return this._selectPlacardByIndex(index + 1);
170     },
171
172     /**
173      * @return {boolean}
174      */
175     _selectPreviousCallFrameOnStack: function()
176     {
177         var index = this._selectedCallFrameIndex();
178         if (index === -1)
179             return false;
180         return this._selectPlacardByIndex(index - 1);
181     },
182
183     /**
184      * @param {number} index
185      * @return {boolean}
186      */
187     _selectPlacardByIndex: function(index)
188     {
189         if (index < 0 || index >= this.placards.length)
190             return false;
191         this._placardSelected(this.placards[index]);
192         return true;
193     },
194
195     /**
196      * @return {number}
197      */
198     _selectedCallFrameIndex: function()
199     {
200         var selectedCallFrame = WebInspector.debuggerModel.selectedCallFrame();
201         if (!selectedCallFrame)
202             return -1;
203         for (var i = 0; i < this.placards.length; ++i) {
204             var placard = this.placards[i];
205             if (placard._callFrame === selectedCallFrame)
206                 return i;
207         }
208         return -1;
209     },
210
211     /**
212      * @param {!WebInspector.CallStackSidebarPane.Placard} placard
213      */
214     _placardSelected: function(placard)
215     {
216         placard.element.scrollIntoViewIfNeeded();
217         this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, placard._callFrame);
218     },
219
220     _copyStackTrace: function()
221     {
222         var text = "";
223         for (var i = 0; i < this.placards.length; ++i) {
224             if (i && this.placards[i]._asyncPlacard !== this.placards[i - 1]._asyncPlacard)
225                 text += this.placards[i]._asyncPlacard.title + "\n";
226             text += this.placards[i].title + " (" + this.placards[i].subtitle + ")\n";
227         }
228         InspectorFrontendHost.copyText(text);
229     },
230
231     /**
232      * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, function(?Event=):boolean)} registerShortcutDelegate
233      */
234     registerShortcuts: function(registerShortcutDelegate)
235     {
236         registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.NextCallFrame, this._selectNextCallFrameOnStack.bind(this));
237         registerShortcutDelegate(WebInspector.ShortcutsScreen.SourcesPanelShortcuts.PrevCallFrame, this._selectPreviousCallFrameOnStack.bind(this));
238     },
239
240     /**
241      * @param {!Element|string} status
242      */
243     setStatus: function(status)
244     {
245         if (!this._statusMessageElement)
246             this._statusMessageElement = this.bodyElement.createChild("div", "info");
247         if (typeof status === "string") {
248             this._statusMessageElement.textContent = status;
249         } else {
250             this._statusMessageElement.removeChildren();
251             this._statusMessageElement.appendChild(status);
252         }
253     },
254
255     _keyDown: function(event)
256     {
257         if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey)
258             return;
259         if (event.keyIdentifier === "Up" && this._selectPreviousCallFrameOnStack() || event.keyIdentifier === "Down" && this._selectNextCallFrameOnStack())
260             event.consume(true);
261     },
262
263     __proto__: WebInspector.SidebarPane.prototype
264 }
265
266 /**
267  * @constructor
268  * @extends {WebInspector.Placard}
269  * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
270  * @param {!WebInspector.Placard=} asyncPlacard
271  */
272 WebInspector.CallStackSidebarPane.Placard = function(callFrame, asyncPlacard)
273 {
274     WebInspector.Placard.call(this, callFrame.functionName || WebInspector.UIString("(anonymous function)"), "");
275     callFrame.createLiveLocation(this._update.bind(this));
276     this._callFrame = callFrame;
277     this._asyncPlacard = asyncPlacard;
278 }
279
280 WebInspector.CallStackSidebarPane.Placard.prototype = {
281     /**
282      * @param {!WebInspector.UILocation} uiLocation
283      */
284     _update: function(uiLocation)
285     {
286         this.subtitle = uiLocation.linkText().trimMiddle(100);
287     },
288
289     __proto__: WebInspector.Placard.prototype
290 }