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