Home | History | Annotate | Download | only in remoting
      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