Home | History | Annotate | Download | only in views
      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/ui/views/script_bubble_view.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/extensions/extension_service.h"
      9 #include "chrome/browser/extensions/extension_system.h"
     10 #include "chrome/browser/extensions/image_loader.h"
     11 #include "chrome/browser/extensions/script_bubble_controller.h"
     12 #include "chrome/browser/extensions/tab_helper.h"
     13 #include "chrome/browser/profiles/profile.h"
     14 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
     15 #include "chrome/common/url_constants.h"
     16 #include "content/public/browser/page_navigator.h"
     17 #include "content/public/browser/web_contents.h"
     18 #include "extensions/common/extension.h"
     19 #include "extensions/common/extension_resource.h"
     20 #include "grit/generated_resources.h"
     21 #include "grit/locale_settings.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 #include "ui/views/controls/image_view.h"
     24 #include "ui/views/controls/label.h"
     25 #include "ui/views/controls/link.h"
     26 #include "ui/views/layout/grid_layout.h"
     27 #include "ui/views/widget/widget.h"
     28 
     29 using content::OpenURLParams;
     30 using content::Referrer;
     31 using content::WebContents;
     32 using extensions::Extension;
     33 using extensions::ExtensionSystem;
     34 using extensions::ScriptBubbleController;
     35 
     36 namespace {
     37 
     38 // Layout constants.
     39 const int kInsetTop = 7;
     40 const int kInsetLeft = 14;
     41 const int kInsetBottom = 11;
     42 const int kPaddingBelowHeadline = 12;
     43 const int kPaddingRightOfIcon = 8;
     44 const int kPaddingBetweenRows = 13;
     45 
     46 }  // namespace
     47 
     48 ////////////////////////////////////////////////////////////////////////////////
     49 // ScriptBubbleView
     50 
     51 ScriptBubbleView::ScriptEntry::ScriptEntry()
     52     : extension_imageview(NULL) {}
     53 
     54 ScriptBubbleView::ScriptBubbleView(views::View* anchor_view,
     55                                    WebContents* web_contents)
     56     : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT),
     57       height_(0),
     58       web_contents_(web_contents) {
     59   // Compensate for built-in vertical padding in the anchor view's image.
     60   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
     61 
     62   extensions::ScriptBubbleController* script_bubble_controller =
     63       GetScriptBubbleController();
     64   const std::set<std::string>& extensions_running_scripts =
     65       script_bubble_controller->extensions_running_scripts();
     66   Profile* profile = Profile::FromBrowserContext(
     67       web_contents_->GetBrowserContext());
     68   ExtensionService* extension_service =
     69       ExtensionSystem::Get(profile)->extension_service();
     70 
     71   size_t i = 0;
     72   for (std::set<std::string>::const_iterator iter =
     73        extensions_running_scripts.begin();
     74        iter != extensions_running_scripts.end(); ++iter, ++i) {
     75     // We specify |true| to get disabled extensions as well, since content
     76     // scripts survive their extensions being disabled.
     77     const Extension* extension =
     78         extension_service->GetExtensionById(*iter, true);
     79     ScriptEntry entry;
     80     entry.extension_id = *iter;
     81     entry.extension_name = UTF8ToUTF16(extension->name());
     82     entries_.push_back(entry);
     83 
     84     int size = extension_misc::EXTENSION_ICON_BITTY;
     85     extensions::ExtensionResource image =
     86         extensions::IconsInfo::GetIconResource(extension,
     87                                                size,
     88                                                ExtensionIconSet::MATCH_BIGGER);
     89     extensions::ImageLoader::Get(profile)->LoadImageAsync(
     90         extension, image, gfx::Size(size, size),
     91         base::Bind(&ScriptBubbleView::OnImageLoaded, AsWeakPtr(), i));
     92   }
     93 }
     94 
     95 ScriptBubbleView::~ScriptBubbleView() {
     96 }
     97 
     98 gfx::Size ScriptBubbleView::GetPreferredSize() {
     99   gfx::Size size(views::Widget::GetLocalizedContentsSize(
    100       IDS_SCRIPTBUBBLE_WIDTH_CHARS,
    101       IDS_SCRIPTBUBBLE_HEIGHT_LINES));
    102   size.set_height(std::max(size.height(), height_));
    103   return size;
    104 }
    105 
    106 void ScriptBubbleView::LinkClicked(views::Link* source, int event_flags) {
    107   std::string link(chrome::kChromeUIExtensionsURL);
    108   link += std::string("?id=") +
    109           entries_[source->id()].extension_id;
    110   web_contents_->OpenURL(OpenURLParams(GURL(link),
    111                                        Referrer(),
    112                                        NEW_FOREGROUND_TAB,
    113                                        content::PAGE_TRANSITION_LINK,
    114                                        false));
    115 }
    116 
    117 void ScriptBubbleView::Init() {
    118   height_ = 0;
    119 
    120   views::GridLayout* layout = new views::GridLayout(this);
    121   SetLayoutManager(layout);
    122   layout->SetInsets(kInsetTop, kInsetLeft, 0, 0);
    123   height_ = kInsetTop + kInsetBottom;
    124 
    125   // Add a column for the heading (one large text column).
    126   views::ColumnSet* columns = layout->AddColumnSet(0);
    127   columns->AddColumn(views::GridLayout::LEADING,   // Horizontal resize.
    128                      views::GridLayout::FILL,      // Vertical resize.
    129                      1,                            // Resize weight.
    130                      views::GridLayout::USE_PREF,  // Size type.
    131                      0,                            // Ignored for USE_PREF.
    132                      0);                           // Minimum size.
    133 
    134   // Add a column set for the extension image plus name.
    135   columns = layout->AddColumnSet(1);
    136   columns->AddColumn(views::GridLayout::LEADING,   // Horizontal resize.
    137                      views::GridLayout::FILL,      // Vertical resize.
    138                      0,                            // Resize weight.
    139                      views::GridLayout::USE_PREF,  // Size type.
    140                      0,                            // Ignored for USE_PREF.
    141                      0);                           // Minimum size.
    142 
    143   columns->AddPaddingColumn(0,                     // resize_percent.
    144                             kPaddingRightOfIcon);  // width.
    145 
    146   columns->AddColumn(views::GridLayout::LEADING,   // Horizontal resize.
    147                      views::GridLayout::FILL,      // Vertical resize.
    148                      1,                            // Resize weight.
    149                      views::GridLayout::USE_PREF,  // Size type.
    150                      0,                            // Ignored for USE_PREF.
    151                      0);                           // Minimum size.
    152 
    153   layout->StartRow(0, 0);
    154   views::Label* heading = new views::Label(
    155       l10n_util::GetStringUTF16(IDS_SCRIPT_BUBBLE_HEADLINE));
    156   layout->AddView(heading);
    157   height_ += heading->GetPreferredSize().height();
    158 
    159   layout->AddPaddingRow(0, kPaddingBelowHeadline);
    160   height_ += kPaddingBelowHeadline;
    161 
    162   for (size_t i = 0; i < entries_.size(); ++i) {
    163     layout->StartRow(0, 1);
    164 
    165     views::ImageView* image_view = new views::ImageView();
    166     entries_[i].extension_imageview = image_view;
    167     image_view->SetImageSize(gfx::Size(16, 16));
    168     image_view->SetImage(
    169         extensions::IconsInfo::GetDefaultExtensionIcon());
    170     layout->AddView(image_view);
    171 
    172     views::Link* link = new views::Link(entries_[i].extension_name);
    173     link->set_id(i);
    174     link->set_listener(this);
    175     layout->AddView(link);
    176 
    177     height_ += std::max(image_view->GetPreferredSize().height(),
    178                         link->GetPreferredSize().height());
    179 
    180     if (i + 1 < entries_.size()) {
    181       layout->AddPaddingRow(0, kPaddingBetweenRows);
    182       height_ += kPaddingBetweenRows;
    183     }
    184   }
    185 
    186   layout->Layout(this);
    187 }
    188 
    189 void ScriptBubbleView::OnImageLoaded(size_t index,
    190                                      const gfx::Image& image) {
    191   if (!image.IsEmpty()) {
    192     const gfx::ImageSkia* image_skia = image.ToImageSkia();
    193     entries_[index].extension_imageview->SetImage(image_skia);
    194   }
    195 }
    196 
    197 ScriptBubbleController* ScriptBubbleView::GetScriptBubbleController() {
    198   extensions::TabHelper* extensions_tab_helper =
    199       extensions::TabHelper::FromWebContents(web_contents_);
    200   return extensions_tab_helper->script_bubble_controller();
    201 }
    202