cloud_print_setup_flow.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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/printing/cloud_print/cloud_print_setup_flow.h" 6 7#include "app/gfx/font_util.h" 8#include "base/json/json_writer.h" 9#include "base/singleton.h" 10#include "base/string_util.h" 11#include "base/utf_string_conversions.h" 12#include "base/values.h" 13#include "chrome/browser/browser_list.h" 14#include "chrome/browser/browser_thread.h" 15#include "chrome/browser/dom_ui/chrome_url_data_manager.h" 16#include "chrome/browser/dom_ui/dom_ui_util.h" 17#if defined(TOOLKIT_GTK) 18#include "chrome/browser/gtk/html_dialog_gtk.h" 19#endif // defined(TOOLKIT_GTK) 20#include "chrome/browser/platform_util.h" 21#include "chrome/browser/prefs/pref_service.h" 22#include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" 23#include "chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h" 24#include "chrome/browser/printing/cloud_print/cloud_print_setup_source.h" 25#include "chrome/browser/printing/cloud_print/cloud_print_url.h" 26#include "chrome/browser/profiles/profile.h" 27#include "chrome/browser/renderer_host/render_view_host.h" 28#include "chrome/browser/service/service_process_control.h" 29#include "chrome/browser/service/service_process_control_manager.h" 30#include "chrome/browser/tab_contents/tab_contents.h" 31#include "chrome/browser/ui/browser.h" 32#include "chrome/browser/ui/browser_window.h" 33#if defined(TOOLKIT_VIEWS) 34#include "chrome/browser/views/browser_dialogs.h" 35#endif // defined(TOOLKIT_GTK) 36#include "chrome/common/net/gaia/gaia_auth_fetcher.h" 37#include "chrome/common/net/gaia/gaia_constants.h" 38#include "chrome/common/net/gaia/google_service_auth_error.h" 39#include "chrome/common/pref_names.h" 40#include "chrome/common/service_messages.h" 41#include "gfx/font.h" 42 43#include "grit/chromium_strings.h" 44#include "grit/locale_settings.h" 45 46static const wchar_t kGaiaLoginIFrameXPath[] = L"//iframe[@id='gaialogin']"; 47static const wchar_t kDoneIframeXPath[] = L"//iframe[@id='setupdone']"; 48 49//////////////////////////////////////////////////////////////////////////////// 50// CloudPrintSetupFlow implementation. 51 52// static 53CloudPrintSetupFlow* CloudPrintSetupFlow::OpenDialog( 54 Profile* profile, Delegate* delegate, gfx::NativeWindow parent_window) { 55 // Set the arguments for showing the gaia login page. 56 DictionaryValue args; 57 args.SetString("user", ""); 58 args.SetInteger("error", 0); 59 args.SetBoolean("editable_user", true); 60 61 bool setup_done = false; 62 if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) && 63 !profile->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty()) 64 setup_done = true; 65 args.SetString("pageToShow", setup_done ? "setupdone" : "cloudprintsetup"); 66 67 std::string json_args; 68 base::JSONWriter::Write(&args, false, &json_args); 69 70 CloudPrintSetupFlow* flow = new CloudPrintSetupFlow(json_args, profile, 71 delegate, setup_done); 72 // We may not always have a browser. This can happen when we are being 73 // invoked in the context of a "token expired" notfication. If we don't have 74 // a brower, use the underlying dialog system to show the dialog without 75 // using a browser. 76 Browser* browser = BrowserList::GetLastActive(); 77 if (browser) { 78 browser->BrowserShowHtmlDialog(flow, parent_window); 79 } else { 80#if defined(TOOLKIT_VIEWS) 81 browser::ShowHtmlDialogView(parent_window, profile, flow); 82#elif defined(TOOLKIT_GTK) 83 HtmlDialogGtk* html_dialog = 84 new HtmlDialogGtk(profile, flow, parent_window); 85 html_dialog->InitDialog(); 86#endif // defined(TOOLKIT_VIEWS) 87 // TODO(sanjeevr): Implement the "no browser" scenario for the Mac. 88 } 89 return flow; 90} 91 92CloudPrintSetupFlow::CloudPrintSetupFlow(const std::string& args, 93 Profile* profile, 94 Delegate* delegate, 95 bool setup_done) 96 : dom_ui_(NULL), 97 dialog_start_args_(args), 98 setup_done_(setup_done), 99 process_control_(NULL), 100 delegate_(delegate) { 101 // TODO(hclam): The data source should be added once. 102 profile_ = profile; 103 BrowserThread::PostTask( 104 BrowserThread::IO, FROM_HERE, 105 NewRunnableMethod(ChromeURLDataManager::GetInstance(), 106 &ChromeURLDataManager::AddDataSource, 107 make_scoped_refptr(new CloudPrintSetupSource()))); 108} 109 110CloudPrintSetupFlow::~CloudPrintSetupFlow() { 111} 112 113void CloudPrintSetupFlow::Focus() { 114 // TODO(pranavk): implement this method. 115 NOTIMPLEMENTED(); 116} 117 118/////////////////////////////////////////////////////////////////////////////// 119// HtmlDialogUIDelegate implementation. 120GURL CloudPrintSetupFlow::GetDialogContentURL() const { 121 return GURL("chrome://cloudprintsetup/setupflow"); 122} 123 124void CloudPrintSetupFlow::GetDOMMessageHandlers( 125 std::vector<DOMMessageHandler*>* handlers) const { 126 // Create the message handler only after we are asked, the caller is 127 // responsible for deleting the objects. 128 handlers->push_back( 129 new CloudPrintSetupMessageHandler( 130 const_cast<CloudPrintSetupFlow*>(this))); 131} 132 133void CloudPrintSetupFlow::GetDialogSize(gfx::Size* size) const { 134 PrefService* prefs = profile_->GetPrefs(); 135 gfx::Font approximate_web_font( 136 UTF8ToWide(prefs->GetString(prefs::kWebKitSansSerifFontFamily)), 137 prefs->GetInteger(prefs::kWebKitDefaultFontSize)); 138 139 if (setup_done_) { 140 *size = gfx::GetLocalizedContentsSizeForFont( 141 IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_WIDTH_CHARS, 142 IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_HEIGHT_LINES, 143 approximate_web_font); 144 } else { 145 *size = gfx::GetLocalizedContentsSizeForFont( 146 IDS_CLOUD_PRINT_SETUP_WIZARD_WIDTH_CHARS, 147 IDS_CLOUD_PRINT_SETUP_WIZARD_HEIGHT_LINES, 148 approximate_web_font); 149 } 150} 151 152// A callback to notify the delegate that the dialog closed. 153void CloudPrintSetupFlow::OnDialogClosed(const std::string& json_retval) { 154 // If we are fetching the token then cancel the request. 155 if (authenticator_.get()) 156 authenticator_->CancelRequest(); 157 158 if (delegate_) { 159 delegate_->OnDialogClosed(); 160 } 161 delete this; 162} 163 164std::string CloudPrintSetupFlow::GetDialogArgs() const { 165 return dialog_start_args_; 166} 167 168void CloudPrintSetupFlow::OnCloseContents(TabContents* source, 169 bool* out_close_dialog) { 170} 171 172std::wstring CloudPrintSetupFlow::GetDialogTitle() const { 173 return UTF16ToWideHack( 174 l10n_util::GetStringUTF16(IDS_CLOUD_PRINT_SETUP_DIALOG_TITLE)); 175} 176 177bool CloudPrintSetupFlow::IsDialogModal() const { 178 // We are always modeless. 179 return false; 180} 181 182bool CloudPrintSetupFlow::ShouldShowDialogTitle() const { 183 return true; 184} 185 186/////////////////////////////////////////////////////////////////////////////// 187// GaiaAuthConsumer implementation. 188void CloudPrintSetupFlow::OnClientLoginFailure( 189 const GoogleServiceAuthError& error) { 190 ShowGaiaFailed(error); 191 authenticator_.reset(); 192} 193 194void CloudPrintSetupFlow::OnClientLoginSuccess( 195 const GaiaAuthConsumer::ClientLoginResult& credentials) { 196 // Save the token for the cloud print proxy. 197 lsid_ = credentials.lsid; 198 199 // Show that Gaia login has succeeded. 200 ShowGaiaSuccessAndSettingUp(); 201 authenticator_.reset(); 202 203 profile_->GetCloudPrintProxyService()->EnableForUser(credentials.lsid, 204 login_); 205 // TODO(sanjeevr): Should we wait and verify that the enable succeeded? 206 ShowSetupDone(); 207} 208 209/////////////////////////////////////////////////////////////////////////////// 210// Methods called by CloudPrintSetupMessageHandler 211void CloudPrintSetupFlow::Attach(DOMUI* dom_ui) { 212 dom_ui_ = dom_ui; 213} 214 215void CloudPrintSetupFlow::OnUserSubmittedAuth(const std::string& user, 216 const std::string& password, 217 const std::string& captcha) { 218 // Save the login name only. 219 login_ = user; 220 221 // Start the authenticator. 222 authenticator_.reset( 223 new GaiaAuthFetcher(this, GaiaConstants::kChromeSource, 224 profile_->GetRequestContext())); 225 226 authenticator_->StartClientLogin(user, password, 227 GaiaConstants::kCloudPrintService, 228 "", captcha, 229 GaiaAuthFetcher::HostedAccountsAllowed); 230} 231 232void CloudPrintSetupFlow::OnUserClickedLearnMore() { 233 dom_ui_->tab_contents()->OpenURL(CloudPrintURL::GetCloudPrintLearnMoreURL(), 234 GURL(), NEW_FOREGROUND_TAB, 235 PageTransition::LINK); 236} 237 238void CloudPrintSetupFlow::OnUserClickedPrintTestPage() { 239 dom_ui_->tab_contents()->OpenURL(CloudPrintURL::GetCloudPrintTestPageURL(), 240 GURL(), NEW_FOREGROUND_TAB, 241 PageTransition::LINK); 242} 243 244/////////////////////////////////////////////////////////////////////////////// 245// Helper methods for showing contents of the DOM UI 246void CloudPrintSetupFlow::ShowGaiaLogin(const DictionaryValue& args) { 247 if (dom_ui_) 248 dom_ui_->CallJavascriptFunction(L"cloudprint.showSetupLogin"); 249 250 std::string json; 251 base::JSONWriter::Write(&args, false, &json); 252 std::wstring javascript = std::wstring(L"showGaiaLogin") + 253 L"(" + UTF8ToWide(json) + L");"; 254 ExecuteJavascriptInIFrame(kGaiaLoginIFrameXPath, javascript); 255} 256 257void CloudPrintSetupFlow::ShowGaiaSuccessAndSettingUp() { 258 ExecuteJavascriptInIFrame(kGaiaLoginIFrameXPath, 259 L"showGaiaSuccessAndSettingUp();"); 260} 261 262void CloudPrintSetupFlow::ShowGaiaFailed(const GoogleServiceAuthError& error) { 263 DictionaryValue args; 264 args.SetString("pageToShow", "cloudprintsetup"); 265 args.SetString("user", ""); 266 args.SetInteger("error", error.state()); 267 args.SetBoolean("editable_user", true); 268 args.SetString("captchaUrl", error.captcha().image_url.spec()); 269 ShowGaiaLogin(args); 270} 271 272void CloudPrintSetupFlow::ShowSetupDone() { 273 setup_done_ = true; 274 string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 275 std::wstring message = 276 UTF16ToWideHack(l10n_util::GetStringFUTF16(IDS_CLOUD_PRINT_SETUP_DONE, 277 product_name, 278 UTF8ToUTF16(login_))); 279 std::wstring javascript = L"cloudprint.setMessage('" + message + L"');"; 280 ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); 281 282 if (dom_ui_) { 283 PrefService* prefs = profile_->GetPrefs(); 284 gfx::Font approximate_web_font( 285 UTF8ToWide(prefs->GetString(prefs::kWebKitSansSerifFontFamily)), 286 prefs->GetInteger(prefs::kWebKitDefaultFontSize)); 287 gfx::Size done_size = gfx::GetLocalizedContentsSizeForFont( 288 IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_WIDTH_CHARS, 289 IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_HEIGHT_LINES, 290 approximate_web_font); 291 292 FundamentalValue new_width(done_size.width()); 293 FundamentalValue new_height(done_size.height()); 294 dom_ui_->CallJavascriptFunction(L"cloudprint.showSetupDone", 295 new_width, new_height); 296 } 297 298 ExecuteJavascriptInIFrame(kDoneIframeXPath, L"cloudprint.onPageShown();"); 299} 300 301void CloudPrintSetupFlow::ExecuteJavascriptInIFrame( 302 const std::wstring& iframe_xpath, 303 const std::wstring& js) { 304 if (dom_ui_) { 305 RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); 306 rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); 307 } 308} 309