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/chromeos/login/simple_web_view_dialog.h" 6 7 #include "ash/shell.h" 8 #include "ash/shell_window_ids.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/app/chrome_command_ids.h" 12 #include "chrome/browser/chromeos/login/captive_portal_window_proxy.h" 13 #include "chrome/browser/command_updater.h" 14 #include "chrome/browser/password_manager/password_manager.h" 15 #include "chrome/browser/password_manager/password_manager_delegate_impl.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h" 19 #include "chrome/browser/ui/toolbar/toolbar_model_impl.h" 20 #include "chrome/browser/ui/view_ids.h" 21 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" 22 #include "chrome/browser/ui/views/reload_button.h" 23 #include "components/web_modal/web_contents_modal_dialog_manager.h" 24 #include "content/public/browser/navigation_controller.h" 25 #include "content/public/browser/navigation_entry.h" 26 #include "content/public/browser/web_contents.h" 27 #include "grit/generated_resources.h" 28 #include "grit/theme_resources.h" 29 #include "ipc/ipc_message.h" 30 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/theme_provider.h" 32 #include "ui/views/background.h" 33 #include "ui/views/controls/webview/webview.h" 34 #include "ui/views/layout/grid_layout.h" 35 #include "ui/views/layout/layout_constants.h" 36 #include "ui/views/view.h" 37 #include "ui/views/widget/widget.h" 38 39 using content::WebContents; 40 using views::GridLayout; 41 using web_modal::WebContentsModalDialogManager; 42 43 namespace { 44 45 const int kLocationBarHeight = 35; 46 // Margin between screen edge and SimpleWebViewDialog border. 47 const int kExternalMargin = 50; 48 // Margin between WebView and SimpleWebViewDialog border. 49 const int kInnerMargin = 2; 50 51 class ToolbarRowView : public views::View { 52 public: 53 ToolbarRowView() { 54 set_background(views::Background::CreateSolidBackground( 55 SkColorSetRGB(0xbe, 0xbe, 0xbe))); 56 } 57 58 virtual ~ToolbarRowView() {} 59 60 void Init(views::View* back, 61 views::View* forward, 62 views::View* reload, 63 views::View* location_bar) { 64 GridLayout* layout = new GridLayout(this); 65 SetLayoutManager(layout); 66 67 // Back button. 68 views::ColumnSet* column_set = layout->AddColumnSet(0); 69 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 70 GridLayout::USE_PREF, 0, 0); 71 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 72 // Forward button. 73 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 74 GridLayout::USE_PREF, 0, 0); 75 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 76 // Reload button. 77 column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, 78 GridLayout::USE_PREF, 0, 0); 79 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 80 // Location bar. 81 column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, 82 GridLayout::FIXED, kLocationBarHeight, 0); 83 column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); 84 85 layout->StartRow(0, 0); 86 layout->AddView(back); 87 layout->AddView(forward); 88 layout->AddView(reload); 89 layout->AddView(location_bar); 90 } 91 92 private: 93 DISALLOW_COPY_AND_ASSIGN(ToolbarRowView); 94 }; 95 96 } // namespace 97 98 namespace chromeos { 99 100 // Stub implementation of ContentSettingBubbleModelDelegate. 101 class StubBubbleModelDelegate : public ContentSettingBubbleModelDelegate { 102 public: 103 StubBubbleModelDelegate() {} 104 virtual ~StubBubbleModelDelegate() {} 105 106 // ContentSettingBubbleModelDelegate implementation: 107 virtual void ShowCollectedCookiesDialog( 108 content::WebContents* web_contents) OVERRIDE { 109 } 110 111 virtual void ShowContentSettingsPage(ContentSettingsType type) OVERRIDE { 112 } 113 114 private: 115 DISALLOW_COPY_AND_ASSIGN(StubBubbleModelDelegate); 116 }; 117 118 // SimpleWebViewDialog class --------------------------------------------------- 119 120 SimpleWebViewDialog::SimpleWebViewDialog(Profile* profile) 121 : profile_(profile), 122 back_(NULL), 123 forward_(NULL), 124 reload_(NULL), 125 location_bar_(NULL), 126 web_view_(NULL), 127 bubble_model_delegate_(new StubBubbleModelDelegate) { 128 command_updater_.reset(new CommandUpdater(this)); 129 command_updater_->UpdateCommandEnabled(IDC_BACK, true); 130 command_updater_->UpdateCommandEnabled(IDC_FORWARD, true); 131 command_updater_->UpdateCommandEnabled(IDC_STOP, true); 132 command_updater_->UpdateCommandEnabled(IDC_RELOAD, true); 133 command_updater_->UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true); 134 command_updater_->UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE, true); 135 } 136 137 SimpleWebViewDialog::~SimpleWebViewDialog() { 138 if (web_view_container_.get()) { 139 // WebView can't be deleted immediately, because it could be on the stack. 140 web_view_->web_contents()->SetDelegate(NULL); 141 base::MessageLoop::current()->DeleteSoon( 142 FROM_HERE, web_view_container_.release()); 143 } 144 } 145 146 void SimpleWebViewDialog::StartLoad(const GURL& url) { 147 web_view_container_.reset(new views::WebView(profile_)); 148 web_view_ = web_view_container_.get(); 149 web_view_->GetWebContents()->SetDelegate(this); 150 web_view_->LoadInitialURL(url); 151 152 WebContents* web_contents = web_view_->GetWebContents(); 153 DCHECK(web_contents); 154 155 // Create the password manager that is needed for the proxy. 156 PasswordManagerDelegateImpl::CreateForWebContents(web_contents); 157 PasswordManager::CreateForWebContentsAndDelegate( 158 web_contents, PasswordManagerDelegateImpl::FromWebContents(web_contents)); 159 160 // LoginHandlerViews uses a constrained window for the password manager view. 161 WebContentsModalDialogManager::CreateForWebContents(web_contents); 162 WebContentsModalDialogManager::FromWebContents(web_contents)-> 163 set_delegate(this); 164 } 165 166 void SimpleWebViewDialog::Init() { 167 set_background(views::Background::CreateSolidBackground(SK_ColorWHITE)); 168 169 // Back/Forward buttons. 170 back_ = new views::ImageButton(this); 171 back_->set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON | 172 ui::EF_MIDDLE_MOUSE_BUTTON); 173 back_->set_tag(IDC_BACK); 174 back_->SetImageAlignment(views::ImageButton::ALIGN_RIGHT, 175 views::ImageButton::ALIGN_TOP); 176 back_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_BACK)); 177 back_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_BACK)); 178 back_->set_id(VIEW_ID_BACK_BUTTON); 179 180 forward_ = new views::ImageButton(this); 181 forward_->set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON | 182 ui::EF_MIDDLE_MOUSE_BUTTON); 183 forward_->set_tag(IDC_FORWARD); 184 forward_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_FORWARD)); 185 forward_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD)); 186 forward_->set_id(VIEW_ID_FORWARD_BUTTON); 187 188 toolbar_model_.reset(new ToolbarModelImpl(this)); 189 190 // Location bar. 191 location_bar_ = new LocationBarView(NULL, profile_, command_updater_.get(), 192 toolbar_model_.get(), this, true); 193 194 // Reload button. 195 reload_ = new ReloadButton(location_bar_, command_updater_.get()); 196 reload_->set_triggerable_event_flags(ui::EF_LEFT_MOUSE_BUTTON | 197 ui::EF_MIDDLE_MOUSE_BUTTON); 198 reload_->set_tag(IDC_RELOAD); 199 reload_->SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_RELOAD)); 200 reload_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_RELOAD)); 201 reload_->set_id(VIEW_ID_RELOAD_BUTTON); 202 203 LoadImages(); 204 205 // Use separate view to setup custom background. 206 ToolbarRowView* toolbar_row = new ToolbarRowView; 207 toolbar_row->Init(back_, forward_, reload_, location_bar_); 208 209 // Layout. 210 GridLayout* layout = new GridLayout(this); 211 SetLayoutManager(layout); 212 213 views::ColumnSet* column_set = layout->AddColumnSet(0); 214 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, 215 GridLayout::FIXED, 0, 0); 216 217 column_set = layout->AddColumnSet(1); 218 column_set->AddPaddingColumn(0, kInnerMargin); 219 column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, 220 GridLayout::FIXED, 0, 0); 221 column_set->AddPaddingColumn(0, kInnerMargin); 222 223 // Setup layout rows. 224 layout->StartRow(0, 0); 225 layout->AddView(toolbar_row); 226 227 layout->AddPaddingRow(0, kInnerMargin); 228 229 layout->StartRow(1, 1); 230 layout->AddView(web_view_container_.release()); 231 layout->AddPaddingRow(0, kInnerMargin); 232 233 location_bar_->Init(); 234 UpdateReload(web_view_->web_contents()->IsLoading(), true); 235 236 Layout(); 237 } 238 239 void SimpleWebViewDialog::Layout() { 240 views::WidgetDelegateView::Layout(); 241 242 FOR_EACH_OBSERVER(web_modal::WebContentsModalDialogHostObserver, 243 observer_list_, 244 OnPositionRequiresUpdate()); 245 } 246 247 views::View* SimpleWebViewDialog::GetContentsView() { 248 return this; 249 } 250 251 views::View* SimpleWebViewDialog::GetInitiallyFocusedView() { 252 return web_view_; 253 } 254 255 void SimpleWebViewDialog::ButtonPressed(views::Button* sender, 256 const ui::Event& event) { 257 command_updater_->ExecuteCommand(sender->tag()); 258 } 259 260 void SimpleWebViewDialog::NavigationStateChanged( 261 const WebContents* source, unsigned changed_flags) { 262 if (location_bar_) { 263 location_bar_->Update(NULL); 264 UpdateButtons(); 265 } 266 } 267 268 content::WebContents* SimpleWebViewDialog::OpenURL( 269 const content::OpenURLParams& params) { 270 // As there are no Browsers right now, this could not actually ever work. 271 NOTIMPLEMENTED(); 272 return NULL; 273 } 274 275 void SimpleWebViewDialog::LoadingStateChanged(WebContents* source) { 276 bool is_loading = source->IsLoading(); 277 UpdateReload(is_loading, false); 278 command_updater_->UpdateCommandEnabled(IDC_STOP, is_loading); 279 } 280 281 WebContents* SimpleWebViewDialog::GetWebContents() const { 282 return NULL; 283 } 284 285 InstantController* SimpleWebViewDialog::GetInstant() { 286 return NULL; 287 } 288 289 views::Widget* SimpleWebViewDialog::CreateViewsBubble( 290 views::BubbleDelegateView* bubble_delegate) { 291 return views::BubbleDelegateView::CreateBubble(bubble_delegate); 292 } 293 294 ContentSettingBubbleModelDelegate* 295 SimpleWebViewDialog::GetContentSettingBubbleModelDelegate() { 296 return bubble_model_delegate_.get(); 297 } 298 299 void SimpleWebViewDialog::ShowWebsiteSettings( 300 content::WebContents* web_contents, 301 const GURL& url, 302 const content::SSLStatus& ssl) { 303 NOTIMPLEMENTED(); 304 // TODO (ygorshenin@,markusheintz@): implement this 305 } 306 307 PageActionImageView* SimpleWebViewDialog::CreatePageActionImageView( 308 LocationBarView* owner, 309 ExtensionAction* action) { 310 // Notreached because SimpleWebViewDialog uses a popup-mode LocationBarView, 311 // and it doesn't create PageActionImageViews. 312 NOTREACHED(); 313 return NULL; 314 } 315 316 void SimpleWebViewDialog::OnInputInProgress(bool in_progress) { 317 } 318 319 content::WebContents* SimpleWebViewDialog::GetActiveWebContents() const { 320 return web_view_->web_contents(); 321 } 322 323 void SimpleWebViewDialog::ExecuteCommandWithDisposition( 324 int id, 325 WindowOpenDisposition) { 326 WebContents* web_contents = web_view_->web_contents(); 327 switch (id) { 328 case IDC_BACK: 329 if (web_contents->GetController().CanGoBack()) { 330 location_bar_->Revert(); 331 web_contents->GetController().GoBack(); 332 } 333 break; 334 case IDC_FORWARD: 335 if (web_contents->GetController().CanGoForward()) { 336 location_bar_->Revert(); 337 web_contents->GetController().GoForward(); 338 } 339 break; 340 case IDC_STOP: 341 web_contents->Stop(); 342 break; 343 case IDC_RELOAD: 344 // Always reload ignoring cache. 345 case IDC_RELOAD_IGNORING_CACHE: 346 case IDC_RELOAD_CLEARING_CACHE: 347 web_contents->GetController().ReloadIgnoringCache(true); 348 break; 349 default: 350 NOTREACHED(); 351 } 352 } 353 354 web_modal::WebContentsModalDialogHost* 355 SimpleWebViewDialog::GetWebContentsModalDialogHost() { 356 return this; 357 } 358 359 gfx::NativeView SimpleWebViewDialog::GetHostView() const { 360 return GetWidget()->GetNativeView(); 361 } 362 363 gfx::Point SimpleWebViewDialog::GetDialogPosition(const gfx::Size& size) { 364 // Center the widget. 365 gfx::Size widget_size = GetWidget()->GetWindowBoundsInScreen().size(); 366 return gfx::Point(widget_size.width() / 2 - size.width() / 2, 367 widget_size.height() / 2 - size.height() / 2); 368 } 369 370 void SimpleWebViewDialog::AddObserver( 371 web_modal::WebContentsModalDialogHostObserver* observer) { 372 if (observer && !observer_list_.HasObserver(observer)) 373 observer_list_.AddObserver(observer); 374 } 375 376 void SimpleWebViewDialog::RemoveObserver( 377 web_modal::WebContentsModalDialogHostObserver* observer) { 378 observer_list_.RemoveObserver(observer); 379 } 380 381 void SimpleWebViewDialog::LoadImages() { 382 ui::ThemeProvider* tp = GetThemeProvider(); 383 384 back_->SetImage(views::CustomButton::STATE_NORMAL, 385 tp->GetImageSkiaNamed(IDR_BACK)); 386 back_->SetImage(views::CustomButton::STATE_HOVERED, 387 tp->GetImageSkiaNamed(IDR_BACK_H)); 388 back_->SetImage(views::CustomButton::STATE_PRESSED, 389 tp->GetImageSkiaNamed(IDR_BACK_P)); 390 back_->SetImage(views::CustomButton::STATE_DISABLED, 391 tp->GetImageSkiaNamed(IDR_BACK_D)); 392 393 forward_->SetImage(views::CustomButton::STATE_NORMAL, 394 tp->GetImageSkiaNamed(IDR_FORWARD)); 395 forward_->SetImage(views::CustomButton::STATE_HOVERED, 396 tp->GetImageSkiaNamed(IDR_FORWARD_H)); 397 forward_->SetImage(views::CustomButton::STATE_PRESSED, 398 tp->GetImageSkiaNamed(IDR_FORWARD_P)); 399 forward_->SetImage(views::CustomButton::STATE_DISABLED, 400 tp->GetImageSkiaNamed(IDR_FORWARD_D)); 401 402 reload_->LoadImages(tp); 403 } 404 405 void SimpleWebViewDialog::UpdateButtons() { 406 const content::NavigationController& navigation_controller = 407 web_view_->web_contents()->GetController(); 408 back_->SetEnabled(navigation_controller.CanGoBack()); 409 forward_->SetEnabled(navigation_controller.CanGoForward()); 410 } 411 412 void SimpleWebViewDialog::UpdateReload(bool is_loading, bool force) { 413 if (reload_) { 414 reload_->ChangeMode( 415 is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, 416 force); 417 } 418 } 419 420 } // namespace chromeos 421