fd7f43010b36322a1cc0a0b435d257963057f9b4
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / devtools_window.h
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_
6 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_
7
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/strings/string16.h"
15 #include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
16 #include "chrome/browser/devtools/devtools_embedder_message_dispatcher.h"
17 #include "chrome/browser/devtools/devtools_file_helper.h"
18 #include "chrome/browser/devtools/devtools_file_system_indexer.h"
19 #include "chrome/browser/devtools/devtools_toggle_action.h"
20 #include "content/public/browser/devtools_client_host.h"
21 #include "content/public/browser/devtools_frontend_host_delegate.h"
22 #include "content/public/browser/notification_observer.h"
23 #include "content/public/browser/notification_registrar.h"
24 #include "content/public/browser/web_contents_delegate.h"
25 #include "ui/gfx/size.h"
26
27 class Browser;
28 class BrowserWindow;
29 class DevToolsControllerTest;
30 class Profile;
31
32 namespace base {
33 class Value;
34 }
35
36 namespace content {
37 class DevToolsAgentHost;
38 class DevToolsClientHost;
39 struct FileChooserParams;
40 class RenderViewHost;
41 class WebContents;
42 }
43
44 namespace IPC {
45 class Message;
46 }
47
48 namespace user_prefs {
49 class PrefRegistrySyncable;
50 }
51
52 class DevToolsWindow : private content::NotificationObserver,
53                        private content::WebContentsDelegate,
54                        private content::DevToolsFrontendHostDelegate,
55                        private DevToolsEmbedderMessageDispatcher::Delegate {
56  public:
57   typedef base::Callback<void(bool)> InfoBarCallback;
58
59   static const char kDevToolsApp[];
60
61   virtual ~DevToolsWindow();
62
63   static std::string GetDevToolsWindowPlacementPrefKey();
64   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
65
66   // Return the DevToolsWindow for the given RenderViewHost if one exists,
67   // otherwise NULL.
68   static DevToolsWindow* GetInstanceForInspectedRenderViewHost(
69       content::RenderViewHost* inspected_rvh);
70
71   // Return the DevToolsWindow for the given WebContents if one exists and is
72   // docked, otherwise NULL. This method will return only fully initialized
73   // window ready to be presented in UI.
74   // For immediately-ready-to-use but maybe not yet fully initialized DevTools
75   // use |GetInstanceForInspectedRenderViewHost| instead.
76   static DevToolsWindow* GetDockedInstanceForInspectedTab(
77       content::WebContents* inspected_tab);
78
79   static bool IsDevToolsWindow(content::RenderViewHost* window_rvh);
80
81   // Open or reveal DevTools window, and perform the specified action.
82   static DevToolsWindow* OpenDevToolsWindow(
83       content::RenderViewHost* inspected_rvh,
84       const DevToolsToggleAction& action);
85
86   // Open or reveal DevTools window, with no special action.
87   static DevToolsWindow* OpenDevToolsWindow(
88       content::RenderViewHost* inspected_rvh);
89
90   static DevToolsWindow* OpenDevToolsWindowForTest(
91       content::RenderViewHost* inspected_rvh, bool is_docked);
92   static DevToolsWindow* OpenDevToolsWindowForTest(
93       Browser* browser, bool is_docked);
94
95   // Perform specified action for current WebContents inside a |browser|.
96   // This may close currently open DevTools window.
97   static DevToolsWindow* ToggleDevToolsWindow(
98       Browser* browser,
99       const DevToolsToggleAction& action);
100
101   // External frontend is always undocked.
102   static void OpenExternalFrontend(
103       Profile* profile,
104       const std::string& frontend_uri,
105       content::DevToolsAgentHost* agent_host);
106
107   // Worker frontend is always undocked.
108   static DevToolsWindow* OpenDevToolsWindowForWorker(
109       Profile* profile,
110       content::DevToolsAgentHost* worker_agent);
111
112   static void InspectElement(
113       content::RenderViewHost* inspected_rvh, int x, int y);
114
115   // content::DevToolsFrontendHostDelegate:
116   virtual void InspectedContentsClosing() OVERRIDE;
117
118   content::WebContents* web_contents() { return web_contents_; }
119   Browser* browser() { return browser_; }  // For tests.
120
121   content::RenderViewHost* GetRenderViewHost();
122
123   // Inspected WebContents is placed over DevTools WebContents in docked mode.
124   // The following method returns the resizing strategy of inspected
125   // WebContents relative to DevTools WebContents.
126   const DevToolsContentsResizingStrategy& GetContentsResizingStrategy() const;
127
128   // Minimum size of the docked DevTools WebContents. This includes
129   // the overlaying inspected WebContents size.
130   gfx::Size GetMinimumSize() const;
131
132   // Sets closure to be called after load is done. If already loaded, calls
133   // closure immediately.
134   void SetLoadCompletedCallback(const base::Closure& closure);
135
136   // BeforeUnload interception ////////////////////////////////////////////////
137
138   // In order to preserve any edits the user may have made in devtools, the
139   // beforeunload event of the inspected page is hooked - devtools gets the
140   // first shot at handling beforeunload and presents a dialog to the user. If
141   // the user accepts the dialog then the script is given a chance to handle
142   // it. This way 2 dialogs may be displayed: one from the devtools asking the
143   // user to confirm that they're ok with their devtools edits going away and
144   // another from the webpage as the result of its beforeunload handler.
145   // The following set of methods handle beforeunload event flow through
146   // devtools window. When the |contents| with devtools opened on them are
147   // getting closed, the following sequence of calls takes place:
148   // 1. |DevToolsWindow::InterceptPageBeforeUnload| is called and indicates
149   //    whether devtools intercept the beforeunload event.
150   //    If InterceptPageBeforeUnload() returns true then the following steps
151   //    will take place; otherwise only step 4 will be reached and none of the
152   //    corresponding functions in steps 2 & 3 will get called.
153   // 2. |DevToolsWindow::InterceptPageBeforeUnload| fires beforeunload event
154   //    for devtools frontend, which will asynchronously call
155   //    |WebContentsDelegate::BeforeUnloadFired| method.
156   //    In case of docked devtools window, devtools are set as a delegate for
157   //    its frontend, so method |DevToolsWindow::BeforeUnloadFired| will be
158   //    called directly.
159   //    If devtools window is undocked it's not set as the delegate so the call
160   //    to BeforeUnloadFired is proxied through HandleBeforeUnload() rather
161   //    than getting called directly.
162   // 3a. If |DevToolsWindow::BeforeUnloadFired| is called with |proceed|=false
163   //     it calls throught to the content's BeforeUnloadFired(), which from the
164   //     WebContents perspective looks the same as the |content|'s own
165   //     beforeunload dialog having had it's 'stay on this page' button clicked.
166   // 3b. If |proceed| = true, then it fires beforeunload event on |contents|
167   //     and everything proceeds as it normally would without the Devtools
168   //     interception.
169   // 4. If the user cancels the dialog put up by either the WebContents or
170   //    devtools frontend, then |contents|'s |BeforeUnloadFired| callback is
171   //    called with the proceed argument set to false, this causes
172   //    |DevToolsWindow::OnPageCloseCancelled| to be called.
173
174   // Devtools window in undocked state is not set as a delegate of
175   // its frontend. Instead, an instance of browser is set as the delegate, and
176   // thus beforeunload event callback from devtools frontend is not delivered
177   // to the instance of devtools window, which is solely responsible for
178   // managing custom beforeunload event flow.
179   // This is a helper method to route callback from
180   // |Browser::BeforeUnloadFired| back to |DevToolsWindow::BeforeUnloadFired|.
181   // * |proceed| - true if the user clicked 'ok' in the beforeunload dialog,
182   //   false otherwise.
183   // * |proceed_to_fire_unload| - output parameter, whether we should continue
184   //   to fire the unload event or stop things here.
185   // Returns true if devtools window is in a state of intercepting beforeunload
186   // event and if it will manage unload process on its own.
187   static bool HandleBeforeUnload(content::WebContents* contents,
188                                  bool proceed,
189                                  bool* proceed_to_fire_unload);
190
191   // Returns true if this contents beforeunload event was intercepted by
192   // devtools and false otherwise. If the event was intercepted, caller should
193   // not fire beforeunlaod event on |contents| itself as devtools window will
194   // take care of it, otherwise caller should continue handling the event as
195   // usual.
196   static bool InterceptPageBeforeUnload(content::WebContents* contents);
197
198   // Returns true if devtools browser has already fired its beforeunload event
199   // as a result of beforeunload event interception.
200   static bool HasFiredBeforeUnloadEventForDevToolsBrowser(Browser* browser);
201
202   // Returns true if devtools window would like to hook beforeunload event
203   // of this |contents|.
204   static bool NeedsToInterceptBeforeUnload(content::WebContents* contents);
205
206   // Notify devtools window that closing of |contents| was cancelled
207   // by user.
208   static void OnPageCloseCanceled(content::WebContents* contents);
209
210  private:
211   friend class DevToolsControllerTest;
212   friend class DevToolsSanityTest;
213   friend class BrowserWindowControllerTest;
214
215   // DevTools initialization typically follows this way:
216   // - Toggle/Open: client call;
217   // - Create;
218   // - ScheduleShow: setup window to be functional, but not yet show;
219   // - DocumentOnLoadCompletedInMainFrame: frontend loaded;
220   // - SetIsDocked: frontend decided on docking state;
221   // - OnLoadCompleted: ready to present frontend;
222   // - Show: actually placing frontend WebContents to a Browser or docked place;
223   // - DoAction: perform action passed in Toggle/Open.
224   enum LoadState {
225     kNotLoaded,
226     kOnLoadFired, // Implies SetIsDocked was not yet called.
227     kIsDockedSet, // Implies DocumentOnLoadCompleted was not yet called.
228     kLoadCompleted
229   };
230
231   DevToolsWindow(Profile* profile,
232                  const GURL& frontend_url,
233                  content::RenderViewHost* inspected_rvh,
234                  bool can_dock);
235
236   static DevToolsWindow* Create(Profile* profile,
237                                 const GURL& frontend_url,
238                                 content::RenderViewHost* inspected_rvh,
239                                 bool shared_worker_frontend,
240                                 bool external_frontend,
241                                 bool can_dock);
242   static GURL GetDevToolsURL(Profile* profile,
243                              const GURL& base_url,
244                              bool shared_worker_frontend,
245                              bool external_frontend,
246                              bool can_dock);
247   static DevToolsWindow* FindDevToolsWindow(content::DevToolsAgentHost*);
248   static DevToolsWindow* AsDevToolsWindow(content::RenderViewHost*);
249   static DevToolsWindow* CreateDevToolsWindowForWorker(Profile* profile);
250   static bool FindInspectedBrowserAndTabIndex(
251       content::WebContents* inspected_web_contents, Browser**, int* tab);
252   static DevToolsWindow* ToggleDevToolsWindow(
253       content::RenderViewHost* inspected_rvh,
254       bool force_open,
255       const DevToolsToggleAction& action);
256
257   // content::NotificationObserver:
258   virtual void Observe(int type,
259                        const content::NotificationSource& source,
260                        const content::NotificationDetails& details) OVERRIDE;
261
262   // content::WebContentsDelegate:
263   virtual content::WebContents* OpenURLFromTab(
264       content::WebContents* source,
265       const content::OpenURLParams& params) OVERRIDE;
266   virtual void AddNewContents(content::WebContents* source,
267                               content::WebContents* new_contents,
268                               WindowOpenDisposition disposition,
269                               const gfx::Rect& initial_pos,
270                               bool user_gesture,
271                               bool* was_blocked) OVERRIDE;
272   virtual void CloseContents(content::WebContents* source) OVERRIDE;
273   virtual void ContentsZoomChange(bool zoom_in) OVERRIDE;
274   virtual void BeforeUnloadFired(content::WebContents* tab,
275                                  bool proceed,
276                                  bool* proceed_to_fire_unload) OVERRIDE;
277   virtual bool PreHandleKeyboardEvent(
278       content::WebContents* source,
279       const content::NativeWebKeyboardEvent& event,
280       bool* is_keyboard_shortcut) OVERRIDE;
281   virtual void HandleKeyboardEvent(
282       content::WebContents* source,
283       const content::NativeWebKeyboardEvent& event) OVERRIDE;
284   virtual content::JavaScriptDialogManager*
285       GetJavaScriptDialogManager() OVERRIDE;
286   virtual content::ColorChooser* OpenColorChooser(
287       content::WebContents* web_contents,
288       SkColor color,
289       const std::vector<content::ColorSuggestion>& suggestions) OVERRIDE;
290   virtual void RunFileChooser(
291       content::WebContents* web_contents,
292       const content::FileChooserParams& params) OVERRIDE;
293   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
294   virtual bool PreHandleGestureEvent(
295       content::WebContents* source,
296       const blink::WebGestureEvent& event) OVERRIDE;
297
298   // content::DevToolsFrontendHostDelegate override:
299   virtual void DispatchOnEmbedder(const std::string& message) OVERRIDE;
300
301   // DevToolsEmbedderMessageDispatcher::Delegate overrides:
302   virtual void ActivateWindow() OVERRIDE;
303   virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
304   virtual void CloseWindow() OVERRIDE;
305   virtual void SetContentsInsets(
306       int left, int top, int right, int bottom) OVERRIDE;
307   virtual void SetContentsResizingStrategy(
308       const gfx::Insets& insets, const gfx::Size& min_size) OVERRIDE;
309   virtual void InspectElementCompleted() OVERRIDE;
310   virtual void MoveWindow(int x, int y) OVERRIDE;
311   virtual void SetIsDocked(bool is_docked) OVERRIDE;
312   virtual void OpenInNewTab(const std::string& url) OVERRIDE;
313   virtual void SaveToFile(const std::string& url,
314                           const std::string& content,
315                           bool save_as) OVERRIDE;
316   virtual void AppendToFile(const std::string& url,
317                             const std::string& content) OVERRIDE;
318   virtual void RequestFileSystems() OVERRIDE;
319   virtual void AddFileSystem() OVERRIDE;
320   virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE;
321   virtual void UpgradeDraggedFileSystemPermissions(
322       const std::string& file_system_url) OVERRIDE;
323   virtual void IndexPath(int request_id,
324                          const std::string& file_system_path) OVERRIDE;
325   virtual void StopIndexing(int request_id) OVERRIDE;
326   virtual void SearchInPath(int request_id,
327                             const std::string& file_system_path,
328                             const std::string& query) OVERRIDE;
329   virtual void ZoomIn() OVERRIDE;
330   virtual void ZoomOut() OVERRIDE;
331   virtual void ResetZoom() OVERRIDE;
332
333   // DevToolsFileHelper callbacks.
334   void FileSavedAs(const std::string& url);
335   void CanceledFileSaveAs(const std::string& url);
336   void AppendedTo(const std::string& url);
337   void FileSystemsLoaded(
338       const std::vector<DevToolsFileHelper::FileSystem>& file_systems);
339   void FileSystemAdded(const DevToolsFileHelper::FileSystem& file_system);
340   void IndexingTotalWorkCalculated(int request_id,
341                                    const std::string& file_system_path,
342                                    int total_work);
343   void IndexingWorked(int request_id,
344                       const std::string& file_system_path,
345                       int worked);
346   void IndexingDone(int request_id, const std::string& file_system_path);
347   void SearchCompleted(int request_id,
348                        const std::string& file_system_path,
349                        const std::vector<std::string>& file_paths);
350   void ShowDevToolsConfirmInfoBar(const base::string16& message,
351                                   const InfoBarCallback& callback);
352
353   void CreateDevToolsBrowser();
354   BrowserWindow* GetInspectedBrowserWindow();
355   void ScheduleShow(const DevToolsToggleAction& action);
356   void Show(const DevToolsToggleAction& action);
357   void DoAction(const DevToolsToggleAction& action);
358   void LoadCompleted();
359   void SetIsDockedAndShowImmediatelyForTest(bool is_docked);
360   void UpdateTheme();
361   void AddDevToolsExtensionsToClient();
362   void CallClientFunction(const std::string& function_name,
363                           const base::Value* arg1,
364                           const base::Value* arg2,
365                           const base::Value* arg3);
366   void UpdateBrowserToolbar();
367   content::WebContents* GetInspectedWebContents();
368   void DocumentOnLoadCompletedInMainFrame();
369
370   class InspectedWebContentsObserver;
371   scoped_ptr<InspectedWebContentsObserver> inspected_contents_observer_;
372   class FrontendWebContentsObserver;
373   friend class FrontendWebContentsObserver;
374   scoped_ptr<FrontendWebContentsObserver> frontend_contents_observer_;
375
376   Profile* profile_;
377   content::WebContents* web_contents_;
378   Browser* browser_;
379   bool is_docked_;
380   bool can_dock_;
381   LoadState load_state_;
382   DevToolsToggleAction action_on_load_;
383   bool ignore_set_is_docked_;
384   content::NotificationRegistrar registrar_;
385   scoped_ptr<content::DevToolsClientHost> frontend_host_;
386   scoped_ptr<DevToolsFileHelper> file_helper_;
387   scoped_refptr<DevToolsFileSystemIndexer> file_system_indexer_;
388   typedef std::map<
389       int,
390       scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob> >
391       IndexingJobsMap;
392   IndexingJobsMap indexing_jobs_;
393   DevToolsContentsResizingStrategy contents_resizing_strategy_;
394   // True if we're in the process of handling a beforeunload event originating
395   // from the inspected webcontents, see InterceptPageBeforeUnload for details.
396   bool intercepted_page_beforeunload_;
397   base::Closure load_completed_callback_;
398
399   scoped_ptr<DevToolsEmbedderMessageDispatcher> embedder_message_dispatcher_;
400   base::WeakPtrFactory<DevToolsWindow> weak_factory_;
401   base::TimeTicks inspect_element_start_time_;
402   DISALLOW_COPY_AND_ASSIGN(DevToolsWindow);
403 };
404
405 #endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_