009cfc05a01143bc997733957475dfc29f158a15
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / inspect_ui.cc
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 #include "chrome/browser/ui/webui/inspect_ui.h"
6
7 #include "base/prefs/pref_service.h"
8 #include "base/stl_util.h"
9 #include "chrome/browser/devtools/devtools_target_impl.h"
10 #include "chrome/browser/devtools/devtools_targets_ui.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser_navigator.h"
13 #include "chrome/browser/ui/singleton_tabs.h"
14 #include "chrome/browser/ui/webui/theme_source.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/common/url_constants.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/notification_types.h"
20 #include "content/public/browser/user_metrics.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_ui.h"
23 #include "content/public/browser/web_ui_data_source.h"
24 #include "content/public/browser/web_ui_message_handler.h"
25 #include "grit/browser_resources.h"
26
27 using content::WebContents;
28 using content::WebUIMessageHandler;
29
30 namespace {
31
32 const char kInitUICommand[]  = "init-ui";
33 const char kInspectCommand[]  = "inspect";
34 const char kActivateCommand[]  = "activate";
35 const char kCloseCommand[]  = "close";
36 const char kReloadCommand[]  = "reload";
37 const char kOpenCommand[]  = "open";
38
39 const char kDiscoverUsbDevicesEnabledCommand[] =
40     "set-discover-usb-devices-enabled";
41 const char kPortForwardingEnabledCommand[] =
42     "set-port-forwarding-enabled";
43 const char kPortForwardingConfigCommand[] = "set-port-forwarding-config";
44
45 const char kPortForwardingDefaultPort[] = "8080";
46 const char kPortForwardingDefaultLocation[] = "localhost:8080";
47
48 class InspectMessageHandler : public WebUIMessageHandler {
49  public:
50   explicit InspectMessageHandler(InspectUI* inspect_ui)
51       : inspect_ui_(inspect_ui) {}
52   virtual ~InspectMessageHandler() {}
53
54  private:
55   // WebUIMessageHandler implementation.
56   virtual void RegisterMessages() OVERRIDE;
57
58   void HandleInitUICommand(const base::ListValue* args);
59   void HandleInspectCommand(const base::ListValue* args);
60   void HandleActivateCommand(const base::ListValue* args);
61   void HandleCloseCommand(const base::ListValue* args);
62   void HandleReloadCommand(const base::ListValue* args);
63   void HandleOpenCommand(const base::ListValue* args);
64   void HandleBooleanPrefChanged(const char* pref_name,
65                                 const base::ListValue* args);
66   void HandlePortForwardingConfigCommand(const base::ListValue* args);
67
68   InspectUI* inspect_ui_;
69
70   DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler);
71 };
72
73 void InspectMessageHandler::RegisterMessages() {
74   web_ui()->RegisterMessageCallback(kInitUICommand,
75       base::Bind(&InspectMessageHandler::HandleInitUICommand,
76                  base::Unretained(this)));
77   web_ui()->RegisterMessageCallback(kInspectCommand,
78       base::Bind(&InspectMessageHandler::HandleInspectCommand,
79                  base::Unretained(this)));
80   web_ui()->RegisterMessageCallback(kActivateCommand,
81       base::Bind(&InspectMessageHandler::HandleActivateCommand,
82                  base::Unretained(this)));
83   web_ui()->RegisterMessageCallback(kCloseCommand,
84       base::Bind(&InspectMessageHandler::HandleCloseCommand,
85                  base::Unretained(this)));
86   web_ui()->RegisterMessageCallback(kDiscoverUsbDevicesEnabledCommand,
87       base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged,
88                   base::Unretained(this),
89                   &prefs::kDevToolsDiscoverUsbDevicesEnabled[0]));
90   web_ui()->RegisterMessageCallback(kPortForwardingEnabledCommand,
91       base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged,
92                  base::Unretained(this),
93                  &prefs::kDevToolsPortForwardingEnabled[0]));
94   web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand,
95       base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand,
96                  base::Unretained(this)));
97   web_ui()->RegisterMessageCallback(kReloadCommand,
98       base::Bind(&InspectMessageHandler::HandleReloadCommand,
99                  base::Unretained(this)));
100   web_ui()->RegisterMessageCallback(kOpenCommand,
101       base::Bind(&InspectMessageHandler::HandleOpenCommand,
102                  base::Unretained(this)));
103 }
104
105 void InspectMessageHandler::HandleInitUICommand(const base::ListValue*) {
106   inspect_ui_->InitUI();
107 }
108
109 static bool ParseStringArgs(const base::ListValue* args,
110                             std::string* arg0,
111                             std::string* arg1,
112                             std::string* arg2 = 0) {
113   int arg_size = args->GetSize();
114   return (!arg0 || (arg_size > 0 && args->GetString(0, arg0))) &&
115          (!arg1 || (arg_size > 1 && args->GetString(1, arg1))) &&
116          (!arg2 || (arg_size > 2 && args->GetString(2, arg2)));
117 }
118
119 void InspectMessageHandler::HandleInspectCommand(const base::ListValue* args) {
120   std::string source;
121   std::string id;
122   if (ParseStringArgs(args, &source, &id))
123     inspect_ui_->Inspect(source, id);
124 }
125
126 void InspectMessageHandler::HandleActivateCommand(const base::ListValue* args) {
127   std::string source;
128   std::string id;
129   if (ParseStringArgs(args, &source, &id))
130     inspect_ui_->Activate(source, id);
131 }
132
133 void InspectMessageHandler::HandleCloseCommand(const base::ListValue* args) {
134   std::string source;
135   std::string id;
136   if (ParseStringArgs(args, &source, &id))
137     inspect_ui_->Close(source, id);
138 }
139
140 void InspectMessageHandler::HandleReloadCommand(const base::ListValue* args) {
141   std::string source;
142   std::string id;
143   if (ParseStringArgs(args, &source, &id))
144     inspect_ui_->Reload(source, id);
145 }
146
147 void InspectMessageHandler::HandleOpenCommand(const base::ListValue* args) {
148   std::string source_id;
149   std::string browser_id;
150   std::string url;
151   if (ParseStringArgs(args, &source_id, &browser_id, &url))
152     inspect_ui_->Open(source_id, browser_id, url);
153 }
154
155 void InspectMessageHandler::HandleBooleanPrefChanged(
156     const char* pref_name,
157     const base::ListValue* args) {
158   Profile* profile = Profile::FromWebUI(web_ui());
159   if (!profile)
160     return;
161
162   bool enabled;
163   if (args->GetSize() == 1 && args->GetBoolean(0, &enabled))
164     profile->GetPrefs()->SetBoolean(pref_name, enabled);
165 }
166
167 void InspectMessageHandler::HandlePortForwardingConfigCommand(
168     const base::ListValue* args) {
169   Profile* profile = Profile::FromWebUI(web_ui());
170   if (!profile)
171     return;
172
173   const base::DictionaryValue* dict_src;
174   if (args->GetSize() == 1 && args->GetDictionary(0, &dict_src))
175     profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src);
176 }
177
178 }  // namespace
179
180 InspectUI::InspectUI(content::WebUI* web_ui)
181     : WebUIController(web_ui) {
182   web_ui->AddMessageHandler(new InspectMessageHandler(this));
183   Profile* profile = Profile::FromWebUI(web_ui);
184   content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource());
185
186   // Set up the chrome://theme/ source.
187   ThemeSource* theme = new ThemeSource(profile);
188   content::URLDataSource::Add(profile, theme);
189 }
190
191 InspectUI::~InspectUI() {
192   StopListeningNotifications();
193 }
194
195 void InspectUI::InitUI() {
196   SetPortForwardingDefaults();
197   StartListeningNotifications();
198   UpdateDiscoverUsbDevicesEnabled();
199   UpdatePortForwardingEnabled();
200   UpdatePortForwardingConfig();
201 }
202
203 void InspectUI::Inspect(const std::string& source_id,
204                         const std::string& target_id) {
205   DevToolsTargetImpl* target = FindTarget(source_id, target_id);
206   if (target)
207     target->Inspect(Profile::FromWebUI(web_ui()));
208 }
209
210 void InspectUI::Activate(const std::string& source_id,
211                          const std::string& target_id) {
212   DevToolsTargetImpl* target = FindTarget(source_id, target_id);
213   if (target)
214     target->Activate();
215 }
216
217 void InspectUI::Close(const std::string& source_id,
218                       const std::string& target_id) {
219   DevToolsTargetImpl* target = FindTarget(source_id, target_id);
220   if (target)
221     target->Close();
222 }
223
224 void InspectUI::Reload(const std::string& source_id,
225                        const std::string& target_id) {
226   DevToolsTargetImpl* target = FindTarget(source_id, target_id);
227   if (target)
228     target->Reload();
229 }
230
231 static void NoOp(DevToolsTargetImpl*) {}
232
233 void InspectUI::Open(const std::string& source_id,
234                      const std::string& browser_id,
235                      const std::string& url) {
236   DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id);
237   if (handler)
238     handler->Open(browser_id, url, base::Bind(&NoOp));
239 }
240
241 void InspectUI::InspectDevices(Browser* browser) {
242   content::RecordAction(base::UserMetricsAction("InspectDevices"));
243   chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
244       browser, GURL(chrome::kChromeUIInspectURL)));
245   params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE;
246   ShowSingletonTabOverwritingNTP(browser, params);
247 }
248
249 void InspectUI::Observe(int type,
250     const content::NotificationSource& source,
251     const content::NotificationDetails& details) {
252   if (source == content::Source<WebContents>(web_ui()->GetWebContents()))
253     StopListeningNotifications();
254 }
255
256 void InspectUI::StartListeningNotifications() {
257   if (!target_handlers_.empty())  // Possible when reloading the page.
258     StopListeningNotifications();
259
260   Profile* profile = Profile::FromWebUI(web_ui());
261
262   DevToolsTargetsUIHandler::Callback callback =
263       base::Bind(&InspectUI::PopulateTargets, base::Unretained(this));
264
265   AddTargetUIHandler(
266       DevToolsTargetsUIHandler::CreateForRenderers(callback));
267   AddTargetUIHandler(
268       DevToolsTargetsUIHandler::CreateForWorkers(callback));
269   AddTargetUIHandler(
270       DevToolsTargetsUIHandler::CreateForAdb(callback, profile));
271
272   port_status_serializer_.reset(
273       new PortForwardingStatusSerializer(
274           base::Bind(&InspectUI::PopulatePortStatus, base::Unretained(this)),
275           profile));
276
277   notification_registrar_.Add(this,
278                               content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
279                               content::NotificationService::AllSources());
280
281   pref_change_registrar_.Init(profile->GetPrefs());
282   pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
283       base::Bind(&InspectUI::UpdateDiscoverUsbDevicesEnabled,
284                  base::Unretained(this)));
285   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled,
286       base::Bind(&InspectUI::UpdatePortForwardingEnabled,
287                  base::Unretained(this)));
288   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig,
289       base::Bind(&InspectUI::UpdatePortForwardingConfig,
290                  base::Unretained(this)));
291 }
292
293 void InspectUI::StopListeningNotifications() {
294   if (target_handlers_.empty())
295     return;
296
297   STLDeleteValues(&target_handlers_);
298
299   port_status_serializer_.reset();
300
301   notification_registrar_.RemoveAll();
302   pref_change_registrar_.RemoveAll();
303 }
304
305 content::WebUIDataSource* InspectUI::CreateInspectUIHTMLSource() {
306   content::WebUIDataSource* source =
307       content::WebUIDataSource::Create(chrome::kChromeUIInspectHost);
308   source->AddResourcePath("inspect.css", IDR_INSPECT_CSS);
309   source->AddResourcePath("inspect.js", IDR_INSPECT_JS);
310   source->SetDefaultResource(IDR_INSPECT_HTML);
311   return source;
312 }
313
314 void InspectUI::UpdateDiscoverUsbDevicesEnabled() {
315   web_ui()->CallJavascriptFunction(
316       "updateDiscoverUsbDevicesEnabled",
317       *GetPrefValue(prefs::kDevToolsDiscoverUsbDevicesEnabled));
318 }
319
320 void InspectUI::UpdatePortForwardingEnabled() {
321   web_ui()->CallJavascriptFunction(
322       "updatePortForwardingEnabled",
323       *GetPrefValue(prefs::kDevToolsPortForwardingEnabled));
324 }
325
326 void InspectUI::UpdatePortForwardingConfig() {
327   web_ui()->CallJavascriptFunction(
328       "updatePortForwardingConfig",
329       *GetPrefValue(prefs::kDevToolsPortForwardingConfig));
330 }
331
332 void InspectUI::SetPortForwardingDefaults() {
333   Profile* profile = Profile::FromWebUI(web_ui());
334   PrefService* prefs = profile->GetPrefs();
335
336   bool default_set;
337   if (!GetPrefValue(prefs::kDevToolsPortForwardingDefaultSet)->
338       GetAsBoolean(&default_set) || default_set) {
339     return;
340   }
341
342   // This is the first chrome://inspect invocation on a fresh profile or after
343   // upgrade from a version that did not have kDevToolsPortForwardingDefaultSet.
344   prefs->SetBoolean(prefs::kDevToolsPortForwardingDefaultSet, true);
345
346   bool enabled;
347   const base::DictionaryValue* config;
348   if (!GetPrefValue(prefs::kDevToolsPortForwardingEnabled)->
349         GetAsBoolean(&enabled) ||
350       !GetPrefValue(prefs::kDevToolsPortForwardingConfig)->
351         GetAsDictionary(&config)) {
352     return;
353   }
354
355   // Do nothing if user already took explicit action.
356   if (enabled || config->size() != 0)
357     return;
358
359   base::DictionaryValue default_config;
360   default_config.SetString(
361       kPortForwardingDefaultPort, kPortForwardingDefaultLocation);
362   prefs->Set(prefs::kDevToolsPortForwardingConfig, default_config);
363 }
364
365 const base::Value* InspectUI::GetPrefValue(const char* name) {
366   Profile* profile = Profile::FromWebUI(web_ui());
367   return profile->GetPrefs()->FindPreference(name)->GetValue();
368 }
369
370 void InspectUI::AddTargetUIHandler(
371     scoped_ptr<DevToolsTargetsUIHandler> handler) {
372   DevToolsTargetsUIHandler* handler_ptr = handler.release();
373   target_handlers_[handler_ptr->source_id()] = handler_ptr;
374 }
375
376 DevToolsTargetsUIHandler* InspectUI::FindTargetHandler(
377     const std::string& source_id) {
378   TargetHandlerMap::iterator it = target_handlers_.find(source_id);
379      return it != target_handlers_.end() ? it->second : NULL;
380 }
381
382 DevToolsTargetImpl* InspectUI::FindTarget(
383     const std::string& source_id, const std::string& target_id) {
384   TargetHandlerMap::iterator it = target_handlers_.find(source_id);
385   return it != target_handlers_.end() ?
386          it->second->GetTarget(target_id) : NULL;
387 }
388
389 void InspectUI::PopulateTargets(const std::string& source,
390                                 scoped_ptr<base::ListValue> targets) {
391   scoped_ptr<base::Value> source_value(base::Value::CreateStringValue(source));
392   web_ui()->CallJavascriptFunction(
393       "populateTargets",
394       *source_value.get(),
395       *targets.get());
396 }
397
398 void InspectUI::PopulatePortStatus(const base::Value& status) {
399   web_ui()->CallJavascriptFunction("populatePortStatus", status);
400 }