Home | History | Annotate | Download | only in views
      1 // Copyright (c) 2011 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/theme_install_bubble_view.h"
      6 
      7 #include "base/utf_string_conversions.h"
      8 #include "content/browser/tab_contents/tab_contents.h"
      9 #include "content/common/notification_service.h"
     10 #include "grit/generated_resources.h"
     11 #include "ui/base/l10n/l10n_util.h"
     12 #include "ui/base/resource/resource_bundle.h"
     13 #include "ui/gfx/canvas_skia.h"
     14 #include "views/widget/widget.h"
     15 
     16 namespace {
     17 
     18 // The roundedness of the edges of our bubble.
     19 static const int kBubbleCornerRadius = 4;
     20 
     21 // Padding around text in popup box.
     22 static const int kTextHorizPadding = 90;
     23 static const int kTextVertPadding = 45;
     24 
     25 // Multiple loads can be started at once.  Only show one bubble, and keep
     26 // track of number of loads happening.  Close bubble when num_loads < 1.
     27 static int num_loads_extant_ = 0;
     28 
     29 }  // namespace
     30 
     31 ThemeInstallBubbleView::ThemeInstallBubbleView(TabContents* tab_contents)
     32     : popup_(NULL) {
     33   if (!tab_contents)
     34     Close();
     35 
     36   text_ = l10n_util::GetStringUTF16(IDS_THEME_LOADING_TITLE);
     37   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
     38   gfx::Font font(rb.GetFont(ResourceBundle::LargeFont));
     39   SetFont(font);
     40 
     41   // We can't check for the size of tab_contents before we've generated
     42   // the string and the font that determine the size of the bubble.
     43   tab_contents->GetContainerBounds(&tab_contents_bounds_);
     44   if (tab_contents_bounds_.height() < GetPreferredSize().height())
     45     Close();
     46 
     47   // Close when theme has been installed.
     48   registrar_.Add(
     49       this,
     50       NotificationType::BROWSER_THEME_CHANGED,
     51       NotificationService::AllSources());
     52 
     53   // Close when we are installing an extension, not a theme.
     54   registrar_.Add(
     55       this,
     56       NotificationType::NO_THEME_DETECTED,
     57       NotificationService::AllSources());
     58   registrar_.Add(
     59       this,
     60       NotificationType::EXTENSION_INSTALLED,
     61       NotificationService::AllSources());
     62   registrar_.Add(
     63       this,
     64       NotificationType::EXTENSION_INSTALL_ERROR,
     65       NotificationService::AllSources());
     66 
     67   // Don't let the bubble overlap the confirm dialog.
     68   registrar_.Add(
     69       this,
     70       NotificationType::EXTENSION_WILL_SHOW_CONFIRM_DIALOG,
     71       NotificationService::AllSources());
     72 
     73   gfx::Rect rc(0, 0, 0, 0);
     74   views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
     75   params.transparent = true;
     76   params.accept_events = false;
     77   popup_ = views::Widget::CreateWidget(params);
     78   popup_->SetOpacity(0xCC);
     79   popup_->Init(tab_contents->GetNativeView(), rc);
     80   popup_->SetContentsView(this);
     81   Reposition();
     82   popup_->Show();
     83 
     84   SchedulePaint();
     85 }
     86 
     87 ThemeInstallBubbleView::~ThemeInstallBubbleView() {
     88   num_loads_extant_ = 0;
     89 }
     90 
     91 gfx::Size ThemeInstallBubbleView::GetPreferredSize() {
     92   return gfx::Size(views::Label::font().GetStringWidth(text_) +
     93       kTextHorizPadding,
     94       ResourceBundle::GetSharedInstance().GetFont(
     95       ResourceBundle::LargeFont).GetHeight() + kTextVertPadding);
     96 }
     97 
     98 void ThemeInstallBubbleView::Reposition() {
     99   if (!popup_)
    100     Close();
    101 
    102   gfx::Size size = GetPreferredSize();
    103   int mid_x = tab_contents_bounds_.x() +
    104       (tab_contents_bounds_.right() - tab_contents_bounds_.x()) / 2;
    105 
    106   int x = base::i18n::IsRTL() ?
    107       mid_x + size.width() / 2 : mid_x - size.width() / 2;
    108   int y = static_cast<int>(tab_contents_bounds_.y() +
    109       (tab_contents_bounds_.bottom() - tab_contents_bounds_.y()) / 2 -
    110       size.height() / 2);
    111 
    112   popup_->SetBounds(gfx::Rect(x, y, size.width(), size.height()));
    113 }
    114 
    115 void ThemeInstallBubbleView::OnPaint(gfx::Canvas* canvas) {
    116   SkScalar rad[8];
    117   for (int i = 0; i < 8; ++i)
    118     rad[i] = SkIntToScalar(kBubbleCornerRadius);
    119 
    120   SkPaint paint;
    121   paint.setStyle(SkPaint::kFill_Style);
    122   paint.setFlags(SkPaint::kAntiAlias_Flag);
    123   paint.setColor(SK_ColorBLACK);
    124 
    125   SkRect rect;
    126   rect.set(0, 0,
    127            SkIntToScalar(width()),
    128            SkIntToScalar(height()));
    129   SkPath path;
    130   path.addRoundRect(rect, rad, SkPath::kCW_Direction);
    131   canvas->AsCanvasSkia()->drawPath(path, paint);
    132 
    133   int text_width = views::Label::font().GetStringWidth(text_);
    134   gfx::Rect body_bounds(kTextHorizPadding / 2, 0, text_width, height());
    135   body_bounds.set_x(GetMirroredXForRect(body_bounds));
    136 
    137   SkColor text_color = SK_ColorWHITE;
    138   canvas->DrawStringInt(text_,
    139                         views::Label::font(),
    140                         text_color,
    141                         body_bounds.x(),
    142                         body_bounds.y(),
    143                         body_bounds.width(),
    144                         body_bounds.height());
    145 }
    146 
    147 void ThemeInstallBubbleView::Close() {
    148   --num_loads_extant_;
    149   if (!popup_) {
    150     num_loads_extant_ = 0;
    151     return;
    152   }
    153   if (num_loads_extant_ < 1) {
    154     registrar_.RemoveAll();
    155     popup_->Close();
    156   }
    157 }
    158 
    159 void ThemeInstallBubbleView::Observe(NotificationType type,
    160                                      const NotificationSource& source,
    161                                      const NotificationDetails& details) {
    162   Close();
    163 }
    164 
    165 // static
    166 void ThemeInstallBubbleView::Show(TabContents* tab_contents) {
    167   ++num_loads_extant_;
    168   if (num_loads_extant_ < 2)
    169     new ThemeInstallBubbleView(tab_contents);
    170 }
    171