Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / components / InspectorView.js
1 /*
2  * Copyright (C) 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.VBox}
34  */
35 WebInspector.InspectorView = function()
36 {
37     WebInspector.VBox.call(this);
38     WebInspector.Dialog.setModalHostView(this);
39     WebInspector.GlassPane.DefaultFocusedViewStack.push(this);
40     this.setMinimumSize(180, 72);
41
42     // DevTools sidebar is a vertical split of panels tabbed pane and a drawer.
43     this._drawerSplitView = new WebInspector.SplitView(false, true, "Inspector.drawerSplitViewState", 200, 200);
44     this._drawerSplitView.hideSidebar();
45     this._drawerSplitView.enableShowModeSaving();
46     this._drawerSplitView.show(this.element);
47
48     this._tabbedPane = new WebInspector.TabbedPane();
49     this._tabbedPane.setRetainTabOrder(true, self.runtime.orderComparator(WebInspector.Panel, "name", "order"));
50     this._tabbedPane.show(this._drawerSplitView.mainElement());
51     this._drawer = new WebInspector.Drawer(this._drawerSplitView);
52
53     // Patch tabbed pane header with toolbar actions.
54     this._toolbarElement = document.createElement("div");
55     this._toolbarElement.className = "toolbar toolbar-background toolbar-colors";
56     var headerElement = this._tabbedPane.headerElement();
57     headerElement.parentElement.insertBefore(this._toolbarElement, headerElement);
58
59     this._leftToolbarElement = this._toolbarElement.createChild("div", "toolbar-controls-left");
60     this._toolbarElement.appendChild(headerElement);
61     this._rightToolbarElement = this._toolbarElement.createChild("div", "toolbar-controls-right");
62     this._toolbarItems = [];
63
64     this._closeButtonToolbarItem = document.createElementWithClass("div", "toolbar-close-button-item");
65     var closeButtonElement = this._closeButtonToolbarItem.createChild("div", "close-button");
66     closeButtonElement.addEventListener("click", InspectorFrontendHost.closeWindow.bind(InspectorFrontendHost), true);
67     this._rightToolbarElement.appendChild(this._closeButtonToolbarItem);
68
69     this._panels = {};
70     // Used by tests.
71     WebInspector["panels"] = this._panels;
72
73     this._history = [];
74     this._historyIterator = -1;
75     document.addEventListener("keydown", this._keyDown.bind(this), false);
76     document.addEventListener("keypress", this._keyPress.bind(this), false);
77     this._panelDescriptors = {};
78
79     // Windows and Mac have two different definitions of '[' and ']', so accept both of each.
80     this._openBracketIdentifiers = ["U+005B", "U+00DB"].keySet();
81     this._closeBracketIdentifiers = ["U+005D", "U+00DD"].keySet();
82     this._lastActivePanelSetting = WebInspector.settings.createSetting("lastActivePanel", "elements");
83
84     // FIXME(399531): enable timelineOnTraceEvents experiment when running layout tests under inspector/tracing/. This code
85     // should be removed along with the old Timeline implementation once we move tracing based Timeline out of experimental.
86     if ("tracing" === this._lastActivePanelSetting.get()) {
87         Runtime.experiments.setEnabled("timelineOnTraceEvents", true);
88         this._lastActivePanelSetting.set("timeline");
89     }
90
91     this._loadPanelDesciptors();
92
93     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.ShowConsole, this.showPanel.bind(this, "console"));
94 };
95
96 WebInspector.InspectorView.prototype = {
97     _loadPanelDesciptors: function()
98     {
99         WebInspector.startBatchUpdate();
100         self.runtime.extensions(WebInspector.Panel).forEach(processPanelExtensions.bind(this));
101         /**
102          * @param {!Runtime.Extension} extension
103          * @this {!WebInspector.InspectorView}
104          */
105         function processPanelExtensions(extension)
106         {
107             this.addPanel(new WebInspector.RuntimeExtensionPanelDescriptor(extension));
108         }
109         WebInspector.endBatchUpdate();
110     },
111
112     /**
113      * @param {!WebInspector.StatusBarItem} item
114      */
115     appendToLeftToolbar: function(item)
116     {
117         this._toolbarItems.push(item);
118         this._leftToolbarElement.appendChild(item.element);
119     },
120
121     /**
122      * @param {!WebInspector.StatusBarItem} item
123      */
124     appendToRightToolbar: function(item)
125     {
126         this._toolbarItems.push(item);
127         this._rightToolbarElement.insertBefore(item.element, this._closeButtonToolbarItem);
128     },
129
130     /**
131      * @param {!WebInspector.PanelDescriptor} panelDescriptor
132      */
133     addPanel: function(panelDescriptor)
134     {
135         var panelName = panelDescriptor.name();
136         this._panelDescriptors[panelName] = panelDescriptor;
137         this._tabbedPane.appendTab(panelName, panelDescriptor.title(), new WebInspector.View());
138         if (this._lastActivePanelSetting.get() === panelName)
139             this._tabbedPane.selectTab(panelName);
140     },
141
142     /**
143      * @param {string} panelName
144      * @return {boolean}
145      */
146     hasPanel: function(panelName)
147     {
148         return !!this._panelDescriptors[panelName];
149     },
150
151     /**
152      * @param {string} panelName
153      * @return {?WebInspector.Panel}
154      */
155     panel: function(panelName)
156     {
157         var panelDescriptor = this._panelDescriptors[panelName];
158         var panelOrder = this._tabbedPane.allTabs();
159         if (!panelDescriptor && panelOrder.length)
160             panelDescriptor = this._panelDescriptors[panelOrder[0]];
161         var panel = panelDescriptor ? panelDescriptor.panel() : null;
162         if (panel)
163             this._panels[panelName] = panel;
164         return panel;
165     },
166
167     /**
168      * @param {boolean} locked
169      */
170     setCurrentPanelLocked: function(locked)
171     {
172         this._currentPanelLocked = locked;
173         this._tabbedPane.setCurrentTabLocked(locked);
174         for (var i = 0; i < this._toolbarItems.length; ++i)
175             this._toolbarItems[i].setEnabled(!locked);
176     },
177
178     /**
179      * @param {string} panelName
180      * @return {?WebInspector.Panel}
181      */
182     showPanel: function(panelName)
183     {
184         if (this._currentPanelLocked)
185             return this._currentPanel === this._panels[panelName] ? this._currentPanel : null;
186
187         var panel = this.panel(panelName);
188         if (panel)
189             this.setCurrentPanel(panel);
190         return panel;
191     },
192
193     /**
194      * @return {!WebInspector.Panel}
195      */
196     currentPanel: function()
197     {
198         return this._currentPanel;
199     },
200
201     showInitialPanel: function()
202     {
203         this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
204         this._tabSelected();
205         this._drawer.initialPanelShown();
206     },
207
208     _tabSelected: function()
209     {
210         var panelName = this._tabbedPane.selectedTabId;
211         if (!panelName)
212             return;
213         var panel = this._panelDescriptors[this._tabbedPane.selectedTabId].panel();
214         this._panels[panelName] = panel;
215         this._tabbedPane.changeTabView(panelName, panel);
216
217         this._currentPanel = panel;
218         this._lastActivePanelSetting.set(panel.name);
219         this._pushToHistory(panel.name);
220         WebInspector.userMetrics.panelShown(panel.name);
221         panel.focus();
222     },
223
224     /**
225      * @param {!WebInspector.Panel} x
226      */
227     setCurrentPanel: function(x)
228     {
229         if (this._currentPanelLocked)
230             return;
231         InspectorFrontendHost.bringToFront();
232         if (this._currentPanel === x)
233             return;
234
235         this._tabbedPane.changeTabView(x.name, x);
236         this._tabbedPane.selectTab(x.name);
237     },
238
239     /**
240      * @param {string} id
241      */
242     closeViewInDrawer: function(id)
243     {
244         this._drawer.closeView(id);
245     },
246
247     /**
248      * @param {string} id
249      * @param {string} title
250      * @param {!WebInspector.View} view
251      */
252     showCloseableViewInDrawer: function(id, title, view)
253     {
254         this._drawer.showCloseableView(id, title, view);
255     },
256
257     showDrawer: function()
258     {
259         this._drawer.showDrawer();
260     },
261
262     /**
263      * @return {boolean}
264      */
265     drawerVisible: function()
266     {
267         return this._drawer.isShowing();
268     },
269
270     /**
271      * @param {string} id
272      * @param {boolean=} immediate
273      */
274     showViewInDrawer: function(id, immediate)
275     {
276         this._drawer.showView(id, immediate);
277     },
278
279     /**
280      * @return {?string}
281      */
282     selectedViewInDrawer: function()
283     {
284         return this._drawer.selectedViewId();
285     },
286
287     closeDrawer: function()
288     {
289         this._drawer.closeDrawer();
290     },
291
292     /**
293      * @return {!Element}
294      */
295     defaultFocusedElement: function()
296     {
297         return this._currentPanel ? this._currentPanel.defaultFocusedElement() : null;
298     },
299
300     _keyPress: function(event)
301     {
302         // BUG 104250: Windows 7 posts a WM_CHAR message upon the Ctrl+']' keypress.
303         // Any charCode < 32 is not going to be a valid keypress.
304         if (event.charCode < 32 && WebInspector.isWin())
305             return;
306         clearTimeout(this._keyDownTimer);
307         delete this._keyDownTimer;
308     },
309
310     _keyDown: function(event)
311     {
312         if (!WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event))
313             return;
314
315         var keyboardEvent = /** @type {!KeyboardEvent} */ (event);
316         // Ctrl/Cmd + 1-9 should show corresponding panel.
317         var panelShortcutEnabled = WebInspector.settings.shortcutPanelSwitch.get();
318         if (panelShortcutEnabled && !event.shiftKey && !event.altKey) {
319             var panelIndex = -1;
320             if (event.keyCode > 0x30 && event.keyCode < 0x3A)
321                 panelIndex = event.keyCode - 0x31;
322             else if (event.keyCode > 0x60 && event.keyCode < 0x6A && keyboardEvent.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD)
323                 panelIndex = event.keyCode - 0x61;
324             if (panelIndex !== -1) {
325                 var panelName = this._tabbedPane.allTabs()[panelIndex];
326                 if (panelName) {
327                     if (!WebInspector.Dialog.currentInstance() && !this._currentPanelLocked)
328                         this.showPanel(panelName);
329                     event.consume(true);
330                 }
331                 return;
332             }
333         }
334
335         // BUG85312: On French AZERTY keyboards, AltGr-]/[ combinations (synonymous to Ctrl-Alt-]/[ on Windows) are used to enter ]/[,
336         // so for a ]/[-related keydown we delay the panel switch using a timer, to see if there is a keypress event following this one.
337         // If there is, we cancel the timer and do not consider this a panel switch.
338         if (!WebInspector.isWin() || (!this._openBracketIdentifiers[event.keyIdentifier] && !this._closeBracketIdentifiers[event.keyIdentifier])) {
339             this._keyDownInternal(event);
340             return;
341         }
342
343         this._keyDownTimer = setTimeout(this._keyDownInternal.bind(this, event), 0);
344     },
345
346     _keyDownInternal: function(event)
347     {
348         if (this._currentPanelLocked)
349             return;
350
351         var direction = 0;
352
353         if (this._openBracketIdentifiers[event.keyIdentifier])
354             direction = -1;
355
356         if (this._closeBracketIdentifiers[event.keyIdentifier])
357             direction = 1;
358
359         if (!direction)
360             return;
361
362         if (!event.shiftKey && !event.altKey) {
363             if (!WebInspector.Dialog.currentInstance())
364                 this._changePanelInDirection(direction);
365             event.consume(true);
366             return;
367         }
368
369         if (event.altKey && this._moveInHistory(direction))
370             event.consume(true)
371     },
372
373     _changePanelInDirection: function(direction)
374     {
375         var panelOrder = this._tabbedPane.allTabs();
376         var index = panelOrder.indexOf(this.currentPanel().name);
377         index = (index + panelOrder.length + direction) % panelOrder.length;
378         this.showPanel(panelOrder[index]);
379     },
380
381     _moveInHistory: function(move)
382     {
383         var newIndex = this._historyIterator + move;
384         if (newIndex >= this._history.length || newIndex < 0)
385             return false;
386
387         this._inHistory = true;
388         this._historyIterator = newIndex;
389         if (!WebInspector.Dialog.currentInstance())
390             this.setCurrentPanel(this._panels[this._history[this._historyIterator]]);
391         delete this._inHistory;
392
393         return true;
394     },
395
396     _pushToHistory: function(panelName)
397     {
398         if (this._inHistory)
399             return;
400
401         this._history.splice(this._historyIterator + 1, this._history.length - this._historyIterator - 1);
402         if (!this._history.length || this._history[this._history.length - 1] !== panelName)
403             this._history.push(panelName);
404         this._historyIterator = this._history.length - 1;
405     },
406
407     onResize: function()
408     {
409         WebInspector.Dialog.modalHostRepositioned();
410     },
411
412     /**
413      * @return {!Element}
414      */
415     topResizerElement: function()
416     {
417         return this._tabbedPane.headerElement();
418     },
419
420     toolbarItemResized: function()
421     {
422         this._tabbedPane.headerResized();
423     },
424
425     __proto__: WebInspector.VBox.prototype
426 };
427
428 /**
429  * @type {!WebInspector.InspectorView}
430  */
431 WebInspector.inspectorView;
432
433 /**
434  * @constructor
435  * @implements {WebInspector.ActionDelegate}
436  */
437 WebInspector.InspectorView.DrawerToggleActionDelegate = function()
438 {
439 }
440
441 WebInspector.InspectorView.DrawerToggleActionDelegate.prototype = {
442     /**
443      * @return {boolean}
444      */
445     handleAction: function()
446     {
447         if (WebInspector.inspectorView.drawerVisible()) {
448             WebInspector.inspectorView.closeDrawer();
449             return true;
450         }
451         WebInspector.inspectorView.showDrawer();
452         return true;
453     }
454 }
455
456 /**
457  * @constructor
458  * @implements {WebInspector.StatusBarItem.Provider}
459  */
460 WebInspector.InspectorView.ToggleDrawerButtonProvider = function()
461 {
462 }
463
464 WebInspector.InspectorView.ToggleDrawerButtonProvider.prototype = {
465     /**
466      * @return {?WebInspector.StatusBarItem}
467      */
468     item: function()
469     {
470         return WebInspector.inspectorView._drawer.toggleButton();
471     }
472 }