Upstream version 9.38.198.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     this._loadPanelDesciptors();
85
86     InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.ShowConsole, this.showPanel.bind(this, "console"));
87 };
88
89 WebInspector.InspectorView.prototype = {
90     _loadPanelDesciptors: function()
91     {
92         WebInspector.startBatchUpdate();
93         self.runtime.extensions(WebInspector.Panel).forEach(processPanelExtensions.bind(this));
94         /**
95          * @param {!Runtime.Extension} extension
96          * @this {!WebInspector.InspectorView}
97          */
98         function processPanelExtensions(extension)
99         {
100             this.addPanel(new WebInspector.RuntimeExtensionPanelDescriptor(extension));
101         }
102         WebInspector.endBatchUpdate();
103     },
104
105     /**
106      * @param {!WebInspector.StatusBarItem} item
107      */
108     appendToLeftToolbar: function(item)
109     {
110         this._toolbarItems.push(item);
111         this._leftToolbarElement.appendChild(item.element);
112     },
113
114     /**
115      * @param {!WebInspector.StatusBarItem} item
116      */
117     appendToRightToolbar: function(item)
118     {
119         this._toolbarItems.push(item);
120         this._rightToolbarElement.insertBefore(item.element, this._closeButtonToolbarItem);
121     },
122
123     /**
124      * @param {!WebInspector.PanelDescriptor} panelDescriptor
125      */
126     addPanel: function(panelDescriptor)
127     {
128         var panelName = panelDescriptor.name();
129         this._panelDescriptors[panelName] = panelDescriptor;
130         this._tabbedPane.appendTab(panelName, panelDescriptor.title(), new WebInspector.View());
131         if (this._lastActivePanelSetting.get() === panelName)
132             this._tabbedPane.selectTab(panelName);
133     },
134
135     /**
136      * @param {string} panelName
137      * @return {boolean}
138      */
139     hasPanel: function(panelName)
140     {
141         return !!this._panelDescriptors[panelName];
142     },
143
144     /**
145      * @param {string} panelName
146      * @return {?WebInspector.Panel}
147      */
148     panel: function(panelName)
149     {
150         var panelDescriptor = this._panelDescriptors[panelName];
151         var panelOrder = this._tabbedPane.allTabs();
152         if (!panelDescriptor && panelOrder.length)
153             panelDescriptor = this._panelDescriptors[panelOrder[0]];
154         var panel = panelDescriptor ? panelDescriptor.panel() : null;
155         if (panel)
156             this._panels[panelName] = panel;
157         return panel;
158     },
159
160     /**
161      * @param {boolean} locked
162      */
163     setCurrentPanelLocked: function(locked)
164     {
165         this._currentPanelLocked = locked;
166         this._tabbedPane.setCurrentTabLocked(locked);
167         for (var i = 0; i < this._toolbarItems.length; ++i)
168             this._toolbarItems[i].setEnabled(!locked);
169     },
170
171     /**
172      * @param {string} panelName
173      * @return {?WebInspector.Panel}
174      */
175     showPanel: function(panelName)
176     {
177         if (this._currentPanelLocked)
178             return this._currentPanel === this._panels[panelName] ? this._currentPanel : null;
179
180         var panel = this.panel(panelName);
181         if (panel)
182             this.setCurrentPanel(panel);
183         return panel;
184     },
185
186     /**
187      * @return {!WebInspector.Panel}
188      */
189     currentPanel: function()
190     {
191         return this._currentPanel;
192     },
193
194     showInitialPanel: function()
195     {
196         this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
197         this._tabSelected();
198         this._drawer.initialPanelShown();
199     },
200
201     _tabSelected: function()
202     {
203         var panelName = this._tabbedPane.selectedTabId;
204         if (!panelName)
205             return;
206         var panel = this._panelDescriptors[this._tabbedPane.selectedTabId].panel();
207         this._panels[panelName] = panel;
208         this._tabbedPane.changeTabView(panelName, panel);
209
210         this._currentPanel = panel;
211         this._lastActivePanelSetting.set(panel.name);
212         this._pushToHistory(panel.name);
213         WebInspector.userMetrics.panelShown(panel.name);
214         panel.focus();
215     },
216
217     /**
218      * @param {!WebInspector.Panel} x
219      */
220     setCurrentPanel: function(x)
221     {
222         if (this._currentPanelLocked)
223             return;
224         InspectorFrontendHost.bringToFront();
225         if (this._currentPanel === x)
226             return;
227
228         this._tabbedPane.changeTabView(x.name, x);
229         this._tabbedPane.selectTab(x.name);
230     },
231
232     /**
233      * @param {string} id
234      */
235     closeViewInDrawer: function(id)
236     {
237         this._drawer.closeView(id);
238     },
239
240     /**
241      * @param {string} id
242      * @param {string} title
243      * @param {!WebInspector.View} view
244      */
245     showCloseableViewInDrawer: function(id, title, view)
246     {
247         this._drawer.showCloseableView(id, title, view);
248     },
249
250     showDrawer: function()
251     {
252         this._drawer.showDrawer();
253     },
254
255     /**
256      * @return {boolean}
257      */
258     drawerVisible: function()
259     {
260         return this._drawer.isShowing();
261     },
262
263     /**
264      * @param {string} id
265      * @param {boolean=} immediate
266      */
267     showViewInDrawer: function(id, immediate)
268     {
269         this._drawer.showView(id, immediate);
270     },
271
272     /**
273      * @return {?string}
274      */
275     selectedViewInDrawer: function()
276     {
277         return this._drawer.selectedViewId();
278     },
279
280     closeDrawer: function()
281     {
282         this._drawer.closeDrawer();
283     },
284
285     /**
286      * @return {!Element}
287      */
288     defaultFocusedElement: function()
289     {
290         return this._currentPanel ? this._currentPanel.defaultFocusedElement() : null;
291     },
292
293     _keyPress: function(event)
294     {
295         // BUG 104250: Windows 7 posts a WM_CHAR message upon the Ctrl+']' keypress.
296         // Any charCode < 32 is not going to be a valid keypress.
297         if (event.charCode < 32 && WebInspector.isWin())
298             return;
299         clearTimeout(this._keyDownTimer);
300         delete this._keyDownTimer;
301     },
302
303     _keyDown: function(event)
304     {
305         if (!WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event))
306             return;
307
308         var keyboardEvent = /** @type {!KeyboardEvent} */ (event);
309         // Ctrl/Cmd + 1-9 should show corresponding panel.
310         var panelShortcutEnabled = WebInspector.settings.shortcutPanelSwitch.get();
311         if (panelShortcutEnabled && !event.shiftKey && !event.altKey) {
312             var panelIndex = -1;
313             if (event.keyCode > 0x30 && event.keyCode < 0x3A)
314                 panelIndex = event.keyCode - 0x31;
315             else if (event.keyCode > 0x60 && event.keyCode < 0x6A && keyboardEvent.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD)
316                 panelIndex = event.keyCode - 0x61;
317             if (panelIndex !== -1) {
318                 var panelName = this._tabbedPane.allTabs()[panelIndex];
319                 if (panelName) {
320                     if (!WebInspector.Dialog.currentInstance() && !this._currentPanelLocked)
321                         this.showPanel(panelName);
322                     event.consume(true);
323                 }
324                 return;
325             }
326         }
327
328         // BUG85312: On French AZERTY keyboards, AltGr-]/[ combinations (synonymous to Ctrl-Alt-]/[ on Windows) are used to enter ]/[,
329         // so for a ]/[-related keydown we delay the panel switch using a timer, to see if there is a keypress event following this one.
330         // If there is, we cancel the timer and do not consider this a panel switch.
331         if (!WebInspector.isWin() || (!this._openBracketIdentifiers[event.keyIdentifier] && !this._closeBracketIdentifiers[event.keyIdentifier])) {
332             this._keyDownInternal(event);
333             return;
334         }
335
336         this._keyDownTimer = setTimeout(this._keyDownInternal.bind(this, event), 0);
337     },
338
339     _keyDownInternal: function(event)
340     {
341         if (this._currentPanelLocked)
342             return;
343
344         var direction = 0;
345
346         if (this._openBracketIdentifiers[event.keyIdentifier])
347             direction = -1;
348
349         if (this._closeBracketIdentifiers[event.keyIdentifier])
350             direction = 1;
351
352         if (!direction)
353             return;
354
355         if (!event.shiftKey && !event.altKey) {
356             if (!WebInspector.Dialog.currentInstance())
357                 this._changePanelInDirection(direction);
358             event.consume(true);
359             return;
360         }
361
362         if (event.altKey && this._moveInHistory(direction))
363             event.consume(true)
364     },
365
366     _changePanelInDirection: function(direction)
367     {
368         var panelOrder = this._tabbedPane.allTabs();
369         var index = panelOrder.indexOf(this.currentPanel().name);
370         index = (index + panelOrder.length + direction) % panelOrder.length;
371         this.showPanel(panelOrder[index]);
372     },
373
374     _moveInHistory: function(move)
375     {
376         var newIndex = this._historyIterator + move;
377         if (newIndex >= this._history.length || newIndex < 0)
378             return false;
379
380         this._inHistory = true;
381         this._historyIterator = newIndex;
382         if (!WebInspector.Dialog.currentInstance())
383             this.setCurrentPanel(this._panels[this._history[this._historyIterator]]);
384         delete this._inHistory;
385
386         return true;
387     },
388
389     _pushToHistory: function(panelName)
390     {
391         if (this._inHistory)
392             return;
393
394         this._history.splice(this._historyIterator + 1, this._history.length - this._historyIterator - 1);
395         if (!this._history.length || this._history[this._history.length - 1] !== panelName)
396             this._history.push(panelName);
397         this._historyIterator = this._history.length - 1;
398     },
399
400     onResize: function()
401     {
402         WebInspector.Dialog.modalHostRepositioned();
403     },
404
405     /**
406      * @return {!Element}
407      */
408     topResizerElement: function()
409     {
410         return this._tabbedPane.headerElement();
411     },
412
413     toolbarItemResized: function()
414     {
415         this._tabbedPane.headerResized();
416     },
417
418     __proto__: WebInspector.VBox.prototype
419 };
420
421 /**
422  * @type {!WebInspector.InspectorView}
423  */
424 WebInspector.inspectorView;
425
426 /**
427  * @constructor
428  * @implements {WebInspector.ActionDelegate}
429  */
430 WebInspector.InspectorView.DrawerToggleActionDelegate = function()
431 {
432 }
433
434 WebInspector.InspectorView.DrawerToggleActionDelegate.prototype = {
435     /**
436      * @return {boolean}
437      */
438     handleAction: function()
439     {
440         if (WebInspector.inspectorView.drawerVisible()) {
441             WebInspector.inspectorView.closeDrawer();
442             return true;
443         }
444         WebInspector.inspectorView.showDrawer();
445         return true;
446     }
447 }
448
449 /**
450  * @constructor
451  * @implements {WebInspector.StatusBarItem.Provider}
452  */
453 WebInspector.InspectorView.ToggleDrawerButtonProvider = function()
454 {
455 }
456
457 WebInspector.InspectorView.ToggleDrawerButtonProvider.prototype = {
458     /**
459      * @return {?WebInspector.StatusBarItem}
460      */
461     item: function()
462     {
463         return WebInspector.inspectorView._drawer.toggleButton();
464     }
465 }