1 // Copyright (c) 2011 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/remoting/setup_flow.h" 6 7 #include "base/json/json_reader.h" 8 #include "base/json/json_writer.h" 9 #include "base/utf_string_conversions.h" 10 #include "base/values.h" 11 #include "chrome/browser/prefs/pref_service.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/remoting/remoting_resources_source.h" 14 #include "chrome/browser/remoting/setup_flow_login_step.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser_list.h" 17 #include "chrome/common/pref_names.h" 18 #include "content/browser/browser_thread.h" 19 #include "content/browser/renderer_host/render_view_host.h" 20 #include "content/browser/tab_contents/tab_contents.h" 21 #include "grit/generated_resources.h" 22 #include "grit/locale_settings.h" 23 #include "ui/base/l10n/l10n_font_util.h" 24 #include "ui/base/l10n/l10n_util.h" 25 #include "ui/gfx/font.h" 26 27 namespace remoting { 28 29 static const wchar_t kDoneIframeXPath[] = L"//iframe[@id='done']"; 30 static const wchar_t kErrorIframeXPath[] = L"//iframe[@id='error']"; 31 32 SetupFlowStep::SetupFlowStep() { } 33 SetupFlowStep::~SetupFlowStep() { } 34 35 SetupFlowStepBase::SetupFlowStepBase() 36 : flow_(NULL), 37 done_(false), 38 next_step_(NULL) { 39 } 40 41 SetupFlowStepBase::~SetupFlowStepBase() { } 42 43 void SetupFlowStepBase::Start(SetupFlow* flow, DoneCallback* done_callback) { 44 done_callback_.reset(done_callback); 45 flow_ = flow; 46 DoStart(); 47 } 48 49 SetupFlowStep* SetupFlowStepBase::GetNextStep() { 50 DCHECK(done_); 51 return next_step_; 52 } 53 54 void SetupFlowStepBase::ExecuteJavascriptInIFrame( 55 const std::wstring& iframe_xpath, const std::wstring& js) { 56 WebUI* web_ui = flow()->web_ui(); 57 DCHECK(web_ui); 58 59 RenderViewHost* rvh = web_ui->tab_contents()->render_view_host(); 60 rvh->ExecuteJavascriptInWebFrame(WideToUTF16Hack(iframe_xpath), 61 WideToUTF16Hack(js)); 62 } 63 64 void SetupFlowStepBase::FinishStep(SetupFlowStep* next_step) { 65 next_step_ = next_step; 66 done_ = true; 67 done_callback_->Run(); 68 } 69 70 SetupFlowErrorStepBase::SetupFlowErrorStepBase() { } 71 SetupFlowErrorStepBase::~SetupFlowErrorStepBase() { } 72 73 void SetupFlowErrorStepBase::HandleMessage(const std::string& message, 74 const Value* arg) { 75 if (message == "Retry") { 76 Retry(); 77 } 78 } 79 80 void SetupFlowErrorStepBase::Cancel() { } 81 82 void SetupFlowErrorStepBase::DoStart() { 83 std::wstring javascript = 84 L"setMessage('" + UTF16ToWide(GetErrorMessage()) + L"');"; 85 ExecuteJavascriptInIFrame(kErrorIframeXPath, javascript); 86 87 flow()->web_ui()->CallJavascriptFunction("showError"); 88 89 ExecuteJavascriptInIFrame(kErrorIframeXPath, L"onPageShown();"); 90 } 91 92 SetupFlowDoneStep::SetupFlowDoneStep() { 93 message_ = l10n_util::GetStringUTF16(IDS_REMOTING_SUCCESS_MESSAGE); 94 } 95 96 SetupFlowDoneStep::SetupFlowDoneStep(const string16& message) 97 : message_(message) { 98 } 99 100 SetupFlowDoneStep::~SetupFlowDoneStep() { } 101 102 void SetupFlowDoneStep::HandleMessage(const std::string& message, 103 const Value* arg) { 104 } 105 106 void SetupFlowDoneStep::Cancel() { } 107 108 void SetupFlowDoneStep::DoStart() { 109 std::wstring javascript = 110 L"setMessage('" + UTF16ToWide(message_) + L"');"; 111 ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); 112 113 flow()->web_ui()->CallJavascriptFunction("showSetupDone"); 114 115 ExecuteJavascriptInIFrame(kDoneIframeXPath, L"onPageShown();"); 116 } 117 118 SetupFlowContext::SetupFlowContext() { } 119 SetupFlowContext::~SetupFlowContext() { } 120 121 SetupFlow::SetupFlow(const std::string& args, 122 Profile* profile, 123 SetupFlowStep* first_step) 124 : web_ui_(NULL), 125 dialog_start_args_(args), 126 profile_(profile), 127 current_step_(first_step) { 128 // TODO(hclam): The data source should be added once. 129 profile->GetChromeURLDataManager()->AddDataSource( 130 new RemotingResourcesSource()); 131 } 132 133 SetupFlow::~SetupFlow() { } 134 135 // static 136 SetupFlow* SetupFlow::OpenSetupDialog(Profile* profile) { 137 // Set the arguments for showing the gaia login page. 138 DictionaryValue args; 139 args.SetString("iframeToShow", "login"); 140 args.SetString("user", ""); 141 args.SetInteger("error", 0); 142 args.SetBoolean("editable_user", true); 143 144 std::string json_args; 145 base::JSONWriter::Write(&args, false, &json_args); 146 147 Browser* b = BrowserList::GetLastActive(); 148 if (!b) 149 return NULL; 150 151 SetupFlow *flow = new SetupFlow(json_args, profile, new SetupFlowLoginStep()); 152 b->BrowserShowHtmlDialog(flow, NULL); 153 return flow; 154 } 155 156 GURL SetupFlow::GetDialogContentURL() const { 157 return GURL("chrome://remotingresources/setup"); 158 } 159 160 void SetupFlow::GetWebUIMessageHandlers( 161 std::vector<WebUIMessageHandler*>* handlers) const { 162 // The called will be responsible for deleting this object. 163 handlers->push_back(const_cast<SetupFlow*>(this)); 164 } 165 166 void SetupFlow::GetDialogSize(gfx::Size* size) const { 167 PrefService* prefs = profile_->GetPrefs(); 168 gfx::Font approximate_web_font( 169 UTF8ToUTF16(prefs->GetString(prefs::kWebKitSansSerifFontFamily)), 170 prefs->GetInteger(prefs::kWebKitDefaultFontSize)); 171 172 // TODO(pranavk) Replace the following SYNC resources with REMOTING Resources. 173 *size = ui::GetLocalizedContentsSizeForFont( 174 IDS_REMOTING_SETUP_WIZARD_WIDTH_CHARS, 175 IDS_REMOTING_SETUP_WIZARD_HEIGHT_LINES, 176 approximate_web_font); 177 } 178 179 // A callback to notify the delegate that the dialog closed. 180 void SetupFlow::OnDialogClosed(const std::string& json_retval) { 181 if (current_step_ != NULL) 182 current_step_->Cancel(); 183 } 184 185 std::string SetupFlow::GetDialogArgs() const { 186 return dialog_start_args_; 187 } 188 189 void SetupFlow::OnCloseContents(TabContents* source, 190 bool* out_close_dialog) { 191 } 192 193 std::wstring SetupFlow::GetDialogTitle() const { 194 return UTF16ToWideHack( 195 l10n_util::GetStringUTF16(IDS_REMOTING_SETUP_DIALOG_TITLE)); 196 } 197 198 bool SetupFlow::IsDialogModal() const { 199 return false; 200 } 201 202 bool SetupFlow::ShouldShowDialogTitle() const { 203 return true; 204 } 205 206 WebUIMessageHandler* SetupFlow::Attach(WebUI* web_ui) { 207 web_ui_ = web_ui; 208 StartCurrentStep(); 209 return WebUIMessageHandler::Attach(web_ui); 210 } 211 212 void SetupFlow::RegisterMessages() { 213 web_ui_->RegisterMessageCallback( 214 "SubmitAuth", NewCallback(this, &SetupFlow::HandleSubmitAuth)); 215 web_ui_->RegisterMessageCallback( 216 "RemotingSetup", NewCallback(this, &SetupFlow::HandleUIMessage)); 217 } 218 219 void SetupFlow::HandleSubmitAuth(const ListValue* args) { 220 Value* first_arg = NULL; 221 if (!args->Get(0, &first_arg)) { 222 NOTREACHED(); 223 return; 224 } 225 226 current_step_->HandleMessage("SubmitAuth", first_arg); 227 } 228 229 void SetupFlow::HandleUIMessage(const ListValue* args) { 230 std::string message; 231 Value* message_value; 232 if (!args->Get(0, &message_value) || 233 !message_value->GetAsString(&message)) { 234 NOTREACHED(); 235 return; 236 } 237 238 // Message argument is optional and set to NULL if it is not 239 // provided by the sending page. 240 Value* arg_value = NULL; 241 if (args->GetSize() >= 2) { 242 if (!args->Get(1, &arg_value)) { 243 NOTREACHED(); 244 return; 245 } 246 } 247 248 current_step_->HandleMessage(message, arg_value); 249 } 250 251 void SetupFlow::StartCurrentStep() { 252 current_step_->Start(this, NewCallback(this, &SetupFlow::OnStepDone)); 253 } 254 255 void SetupFlow::OnStepDone() { 256 SetupFlowStep* next_step = current_step_->GetNextStep(); 257 258 if (current_step_.get()) { 259 // Can't destroy current step here. Schedule it to be destroyed later. 260 BrowserThread::PostTask( 261 BrowserThread::UI, FROM_HERE, 262 new DeleteTask<SetupFlowStep>(current_step_.release())); 263 } 264 265 current_step_.reset(next_step); 266 StartCurrentStep(); 267 } 268 269 } // namespace remoting 270