Home | History | Annotate | Download | only in autofill
      1 // Copyright 2013 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/tooltip_icon.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/timer/timer.h"
      9 #include "chrome/browser/ui/views/autofill/info_bubble.h"
     10 #include "grit/theme_resources.h"
     11 #include "ui/base/resource/resource_bundle.h"
     12 #include "ui/views/bubble/bubble_frame_view.h"
     13 #include "ui/views/mouse_watcher_view_host.h"
     14 #include "ui/views/painter.h"
     15 
     16 namespace autofill {
     17 
     18 namespace {
     19 
     20 gfx::Insets GetPreferredInsets(views::View* view) {
     21   gfx::Size pref_size = view->GetPreferredSize();
     22   gfx::Rect local_bounds = view->GetLocalBounds();
     23   gfx::Point origin = local_bounds.CenterPoint();
     24   origin.Offset(-pref_size.width() / 2, -pref_size.height() / 2);
     25   return gfx::Insets(origin.y(),
     26                      origin.x(),
     27                      local_bounds.bottom() - (origin.y() + pref_size.height()),
     28                      local_bounds.right() - (origin.x() + pref_size.width()));
     29 }
     30 
     31 // An info bubble with some extra positioning magic for tooltip icons.
     32 class TooltipBubble : public InfoBubble {
     33  public:
     34   TooltipBubble(views::View* anchor, const base::string16& message)
     35       : InfoBubble(anchor, message) {}
     36   virtual ~TooltipBubble() {}
     37 
     38  protected:
     39   // InfoBubble:
     40   virtual gfx::Rect GetAnchorRect() OVERRIDE {
     41     gfx::Rect bounds = views::BubbleDelegateView::GetAnchorRect();
     42     bounds.Inset(GetPreferredInsets(anchor()));
     43     return bounds;
     44   }
     45 
     46  private:
     47   DISALLOW_COPY_AND_ASSIGN(TooltipBubble);
     48 };
     49 
     50 }  // namespace
     51 
     52 TooltipIcon::TooltipIcon(const base::string16& tooltip)
     53     : tooltip_(tooltip),
     54       mouse_inside_(false),
     55       bubble_(NULL),
     56       observer_(this) {
     57   ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON);
     58   SetFocusable(true);
     59 }
     60 
     61 TooltipIcon::~TooltipIcon() {
     62   HideBubble();
     63 }
     64 
     65 // static
     66 const char TooltipIcon::kViewClassName[] = "autofill/TooltipIcon";
     67 
     68 const char* TooltipIcon::GetClassName() const {
     69   return TooltipIcon::kViewClassName;
     70 }
     71 
     72 void TooltipIcon::OnMouseEntered(const ui::MouseEvent& event) {
     73   mouse_inside_ = true;
     74   show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), this,
     75                     &TooltipIcon::ShowBubble);
     76 }
     77 
     78 void TooltipIcon::OnMouseExited(const ui::MouseEvent& event) {
     79   show_timer_.Stop();
     80 }
     81 
     82 void TooltipIcon::OnGestureEvent(ui::GestureEvent* event) {
     83   if (event->type() == ui::ET_GESTURE_TAP) {
     84     ShowBubble();
     85     event->SetHandled();
     86   }
     87 }
     88 
     89 void TooltipIcon::OnBoundsChanged(const gfx::Rect& prev_bounds) {
     90   SetFocusPainter(views::Painter::CreateDashedFocusPainterWithInsets(
     91                       GetPreferredInsets(this)));
     92 }
     93 
     94 void TooltipIcon::OnFocus() {
     95   ShowBubble();
     96 }
     97 
     98 void TooltipIcon::OnBlur() {
     99   if (!mouse_inside_)
    100     HideBubble();
    101 }
    102 
    103 void TooltipIcon::MouseMovedOutOfHost() {
    104   if (IsMouseHovered()) {
    105     mouse_watcher_->Start();
    106     return;
    107   }
    108 
    109   mouse_inside_ = false;
    110   if (!HasFocus())
    111     HideBubble();
    112 }
    113 
    114 void TooltipIcon::ChangeImageTo(int idr) {
    115   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
    116   SetImage(rb.GetImageNamed(idr).ToImageSkia());
    117 }
    118 
    119 void TooltipIcon::ShowBubble() {
    120   if (bubble_)
    121     return;
    122 
    123   ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON_H);
    124 
    125   bubble_ = new TooltipBubble(this, tooltip_);
    126   // When shown due to a gesture event, close on deactivate (i.e. don't use
    127   // "focusless").
    128   bubble_->set_use_focusless(mouse_inside_ || HasFocus());
    129 
    130   bubble_->Show();
    131   observer_.Add(bubble_->GetWidget());
    132 
    133   if (mouse_inside_) {
    134     views::View* frame = bubble_->GetWidget()->non_client_view()->frame_view();
    135     scoped_ptr<views::MouseWatcherHost> host(
    136         new views::MouseWatcherViewHost(frame, gfx::Insets()));
    137     mouse_watcher_.reset(new views::MouseWatcher(host.release(), this));
    138     mouse_watcher_->Start();
    139   }
    140 }
    141 
    142 void TooltipIcon::HideBubble() {
    143   if (bubble_)
    144     bubble_->Hide();
    145 }
    146 
    147 void TooltipIcon::OnWidgetDestroyed(views::Widget* widget) {
    148   observer_.Remove(widget);
    149 
    150   ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON);
    151   mouse_watcher_.reset();
    152   bubble_ = NULL;
    153 }
    154 
    155 }  // namespace autofill
    156