autofill_popup_base_view.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
1// Copyright 2014 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/ui/views/autofill/autofill_popup_base_view.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/message_loop/message_loop.h" 10#include "chrome/browser/ui/autofill/popup_constants.h" 11#include "ui/views/border.h" 12#include "ui/views/widget/widget.h" 13#include "ui/wm/core/window_animations.h" 14 15namespace autofill { 16 17const SkColor AutofillPopupBaseView::kBorderColor = 18 SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE); 19const SkColor AutofillPopupBaseView::kHoveredBackgroundColor = 20 SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD); 21const SkColor AutofillPopupBaseView::kItemTextColor = 22 SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); 23const SkColor AutofillPopupBaseView::kPopupBackground = 24 SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF); 25const SkColor AutofillPopupBaseView::kValueTextColor = 26 SkColorSetARGB(0xFF, 0x00, 0x00, 0x00); 27const SkColor AutofillPopupBaseView::kWarningTextColor = 28 SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); 29 30AutofillPopupBaseView::AutofillPopupBaseView( 31 AutofillPopupViewDelegate* delegate, 32 views::Widget* observing_widget) 33 : delegate_(delegate), 34 observing_widget_(observing_widget), 35 weak_ptr_factory_(this) {} 36 37AutofillPopupBaseView::~AutofillPopupBaseView() { 38 if (delegate_) { 39 delegate_->ViewDestroyed(); 40 41 RemoveObserver(); 42 } 43} 44 45void AutofillPopupBaseView::DoShow() { 46 const bool initialize_widget = !GetWidget(); 47 if (initialize_widget) { 48 observing_widget_->AddObserver(this); 49 50 views::FocusManager* focus_manager = observing_widget_->GetFocusManager(); 51 focus_manager->RegisterAccelerator( 52 ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE), 53 ui::AcceleratorManager::kNormalPriority, 54 this); 55 focus_manager->RegisterAccelerator( 56 ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE), 57 ui::AcceleratorManager::kNormalPriority, 58 this); 59 60 // The widget is destroyed by the corresponding NativeWidget, so we use 61 // a weak pointer to hold the reference and don't have to worry about 62 // deletion. 63 views::Widget* widget = new views::Widget; 64 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 65 params.delegate = this; 66 params.parent = container_view(); 67 widget->Init(params); 68 widget->SetContentsView(this); 69 70 // No animation for popup appearance (too distracting). 71 wm::SetWindowVisibilityAnimationTransition( 72 widget->GetNativeView(), wm::ANIMATE_HIDE); 73 } 74 75 SetBorder(views::Border::CreateSolidBorder(kPopupBorderThickness, 76 kBorderColor)); 77 78 DoUpdateBoundsAndRedrawPopup(); 79 GetWidget()->Show(); 80 81 // Showing the widget can change native focus (which would result in an 82 // immediate hiding of the popup). Only start observing after shown. 83 if (initialize_widget) 84 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); 85} 86 87void AutofillPopupBaseView::DoHide() { 88 // The controller is no longer valid after it hides us. 89 delegate_ = NULL; 90 91 RemoveObserver(); 92 93 if (GetWidget()) { 94 // Don't call CloseNow() because some of the functions higher up the stack 95 // assume the the widget is still valid after this point. 96 // http://crbug.com/229224 97 // NOTE: This deletes |this|. 98 GetWidget()->Close(); 99 } else { 100 delete this; 101 } 102} 103 104void AutofillPopupBaseView::RemoveObserver() { 105 observing_widget_->GetFocusManager()->UnregisterAccelerators(this); 106 observing_widget_->RemoveObserver(this); 107 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); 108} 109 110void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { 111 GetWidget()->SetBounds(delegate_->popup_bounds()); 112 SchedulePaint(); 113} 114 115void AutofillPopupBaseView::OnNativeFocusChange( 116 gfx::NativeView focused_before, 117 gfx::NativeView focused_now) { 118 if (GetWidget() && GetWidget()->GetNativeView() != focused_now) 119 HideController(); 120} 121 122void AutofillPopupBaseView::OnWidgetBoundsChanged(views::Widget* widget, 123 const gfx::Rect& new_bounds) { 124 DCHECK_EQ(widget, observing_widget_); 125 HideController(); 126} 127 128void AutofillPopupBaseView::OnMouseCaptureLost() { 129 ClearSelection(); 130} 131 132bool AutofillPopupBaseView::OnMouseDragged(const ui::MouseEvent& event) { 133 if (HitTestPoint(event.location())) { 134 SetSelection(event.location()); 135 136 // We must return true in order to get future OnMouseDragged and 137 // OnMouseReleased events. 138 return true; 139 } 140 141 // If we move off of the popup, we lose the selection. 142 ClearSelection(); 143 return false; 144} 145 146void AutofillPopupBaseView::OnMouseExited(const ui::MouseEvent& event) { 147 // Pressing return causes the cursor to hide, which will generate an 148 // OnMouseExited event. Pressing return should activate the current selection 149 // via AcceleratorPressed, so we need to let that run first. 150 base::MessageLoop::current()->PostTask( 151 FROM_HERE, 152 base::Bind(&AutofillPopupBaseView::ClearSelection, 153 weak_ptr_factory_.GetWeakPtr())); 154} 155 156void AutofillPopupBaseView::OnMouseMoved(const ui::MouseEvent& event) { 157 if (HitTestPoint(event.location())) 158 SetSelection(event.location()); 159 else 160 ClearSelection(); 161} 162 163bool AutofillPopupBaseView::OnMousePressed(const ui::MouseEvent& event) { 164 return event.GetClickCount() == 1; 165} 166 167void AutofillPopupBaseView::OnMouseReleased(const ui::MouseEvent& event) { 168 // We only care about the left click. 169 if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) 170 AcceptSelection(event.location()); 171} 172 173void AutofillPopupBaseView::OnGestureEvent(ui::GestureEvent* event) { 174 switch (event->type()) { 175 case ui::ET_GESTURE_TAP_DOWN: 176 case ui::ET_GESTURE_SCROLL_BEGIN: 177 case ui::ET_GESTURE_SCROLL_UPDATE: 178 if (HitTestPoint(event->location())) 179 SetSelection(event->location()); 180 else 181 ClearSelection(); 182 break; 183 case ui::ET_GESTURE_TAP: 184 case ui::ET_GESTURE_SCROLL_END: 185 if (HitTestPoint(event->location())) 186 AcceptSelection(event->location()); 187 else 188 ClearSelection(); 189 break; 190 case ui::ET_GESTURE_TAP_CANCEL: 191 case ui::ET_SCROLL_FLING_START: 192 ClearSelection(); 193 break; 194 default: 195 return; 196 } 197 event->SetHandled(); 198} 199 200bool AutofillPopupBaseView::AcceleratorPressed( 201 const ui::Accelerator& accelerator) { 202 DCHECK_EQ(accelerator.modifiers(), ui::EF_NONE); 203 204 if (accelerator.key_code() == ui::VKEY_ESCAPE) { 205 HideController(); 206 return true; 207 } 208 209 if (accelerator.key_code() == ui::VKEY_RETURN) 210 return delegate_->AcceptSelectedLine(); 211 212 NOTREACHED(); 213 return false; 214} 215 216void AutofillPopupBaseView::SetSelection(const gfx::Point& point) { 217 if (delegate_) 218 delegate_->SetSelectionAtPoint(point); 219} 220 221void AutofillPopupBaseView::AcceptSelection(const gfx::Point& point) { 222 if (!delegate_) 223 return; 224 225 delegate_->SetSelectionAtPoint(point); 226 delegate_->AcceptSelectedLine(); 227} 228 229void AutofillPopupBaseView::ClearSelection() { 230 if (delegate_) 231 delegate_->SelectionCleared(); 232} 233 234void AutofillPopupBaseView::HideController() { 235 if (delegate_) 236 delegate_->Hide(); 237} 238 239gfx::NativeView AutofillPopupBaseView::container_view() { 240 return delegate_->container_view(); 241} 242 243} // namespace autofill 244