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/collected_cookies_win.h"
      6 
      7 #include "chrome/browser/cookies_tree_model.h"
      8 #include "chrome/browser/profiles/profile.h"
      9 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
     10 #include "chrome/browser/ui/views/cookie_info_view.h"
     11 #include "content/browser/tab_contents/tab_contents.h"
     12 #include "content/common/notification_details.h"
     13 #include "content/common/notification_source.h"
     14 #include "grit/generated_resources.h"
     15 #include "grit/locale_settings.h"
     16 #include "grit/theme_resources.h"
     17 #include "ui/base/l10n/l10n_util.h"
     18 #include "ui/base/resource/resource_bundle.h"
     19 #include "ui/gfx/color_utils.h"
     20 #include "views/controls/button/native_button.h"
     21 #include "views/controls/image_view.h"
     22 #include "views/controls/label.h"
     23 #include "views/controls/separator.h"
     24 #include "views/controls/tabbed_pane/tabbed_pane.h"
     25 #include "views/layout/box_layout.h"
     26 #include "views/layout/grid_layout.h"
     27 #include "views/layout/layout_constants.h"
     28 #include "views/widget/root_view.h"
     29 #include "views/widget/widget_win.h"
     30 #include "views/window/window.h"
     31 
     32 namespace browser {
     33 
     34 // Declared in browser_dialogs.h so others don't have to depend on our header.
     35 void ShowCollectedCookiesDialog(gfx::NativeWindow parent_window,
     36                                 TabContents* tab_contents) {
     37   // Deletes itself on close.
     38   new CollectedCookiesWin(parent_window, tab_contents);
     39 }
     40 
     41 }  // namespace browser
     42 
     43 namespace {
     44 // Spacing between the infobar frame and its contents.
     45 const int kInfobarVerticalPadding = 3;
     46 const int kInfobarHorizontalPadding = 8;
     47 
     48 // Width of the infobar frame.
     49 const int kInfobarBorderSize = 1;
     50 
     51 // Dimensions of the tree views.
     52 const int kTreeViewWidth = 400;
     53 const int kTreeViewHeight = 125;
     54 
     55 }  // namespace
     56 
     57 // A custom view that conditionally displays an infobar.
     58 class InfobarView : public views::View {
     59  public:
     60   InfobarView() {
     61     content_ = new views::View;
     62     SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
     63     views::Border* border = views::Border::CreateSolidBorder(
     64         kInfobarBorderSize, border_color);
     65     content_->set_border(border);
     66 
     67     ResourceBundle& rb = ResourceBundle::GetSharedInstance();
     68     info_image_ = new views::ImageView();
     69     info_image_->SetImage(rb.GetBitmapNamed(IDR_INFO));
     70     label_ = new views::Label();
     71   }
     72   virtual ~InfobarView() {}
     73 
     74   // Update the visibility of the infobar. If |is_visible| is true, a rule for
     75   // |setting| on |domain_name| was created.
     76   void UpdateVisibility(bool is_visible,
     77                         ContentSetting setting,
     78                         const std::wstring& domain_name) {
     79     if (!is_visible) {
     80       SetVisible(false);
     81       return;
     82     }
     83 
     84     std::wstring label;
     85     switch (setting) {
     86       case CONTENT_SETTING_BLOCK:
     87         label = UTF16ToWide(l10n_util::GetStringFUTF16(
     88             IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED,
     89             WideToUTF16(domain_name)));
     90         break;
     91 
     92       case CONTENT_SETTING_ALLOW:
     93         label = UTF16ToWide(l10n_util::GetStringFUTF16(
     94             IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED,
     95             WideToUTF16(domain_name)));
     96         break;
     97 
     98       case CONTENT_SETTING_SESSION_ONLY:
     99         label = UTF16ToWide(l10n_util::GetStringFUTF16(
    100             IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED,
    101             WideToUTF16(domain_name)));
    102         break;
    103 
    104       default:
    105         NOTREACHED();
    106     }
    107     label_->SetText(label);
    108     content_->Layout();
    109     SetVisible(true);
    110   }
    111 
    112  private:
    113   // Initialize contents and layout.
    114   void Init() {
    115     AddChildView(content_);
    116     content_->SetLayoutManager(
    117         new views::BoxLayout(views::BoxLayout::kHorizontal,
    118                              kInfobarHorizontalPadding,
    119                              kInfobarVerticalPadding,
    120                              views::kRelatedControlSmallHorizontalSpacing));
    121     content_->AddChildView(info_image_);
    122     content_->AddChildView(label_);
    123     UpdateVisibility(false, CONTENT_SETTING_BLOCK, std::wstring());
    124   }
    125 
    126   // views::View overrides.
    127   virtual gfx::Size GetPreferredSize() {
    128     if (!IsVisible())
    129       return gfx::Size();
    130 
    131     // Add space around the banner.
    132     gfx::Size size(content_->GetPreferredSize());
    133     size.Enlarge(0, 2 * views::kRelatedControlVerticalSpacing);
    134     return size;
    135   }
    136 
    137   virtual void Layout() {
    138     content_->SetBounds(
    139         0, views::kRelatedControlVerticalSpacing,
    140         width(), height() - views::kRelatedControlVerticalSpacing);
    141   }
    142 
    143   virtual void ViewHierarchyChanged(bool is_add,
    144                                     views::View* parent,
    145                                     views::View* child) {
    146     if (is_add && child == this)
    147       Init();
    148   }
    149 
    150   // Holds the info icon image and text label and renders the border.
    151   views::View* content_;
    152   // Info icon image.
    153   views::ImageView* info_image_;
    154   // The label responsible for rendering the text.
    155   views::Label* label_;
    156 
    157   DISALLOW_COPY_AND_ASSIGN(InfobarView);
    158 };
    159 
    160 ///////////////////////////////////////////////////////////////////////////////
    161 // CollectedCookiesWin, constructor and destructor:
    162 
    163 CollectedCookiesWin::CollectedCookiesWin(gfx::NativeWindow parent_window,
    164                                          TabContents* tab_contents)
    165     : tab_contents_(tab_contents),
    166       allowed_label_(NULL),
    167       blocked_label_(NULL),
    168       allowed_cookies_tree_(NULL),
    169       blocked_cookies_tree_(NULL),
    170       block_allowed_button_(NULL),
    171       allow_blocked_button_(NULL),
    172       for_session_blocked_button_(NULL),
    173       infobar_(NULL),
    174       status_changed_(false) {
    175   TabSpecificContentSettings* content_settings =
    176       tab_contents->GetTabSpecificContentSettings();
    177   registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN,
    178                  Source<TabSpecificContentSettings>(content_settings));
    179 
    180   Init();
    181 
    182   window_ = tab_contents_->CreateConstrainedDialog(this);
    183 }
    184 
    185 CollectedCookiesWin::~CollectedCookiesWin() {
    186   allowed_cookies_tree_->SetModel(NULL);
    187   blocked_cookies_tree_->SetModel(NULL);
    188 }
    189 
    190 void CollectedCookiesWin::Init() {
    191   using views::GridLayout;
    192 
    193   GridLayout* layout = GridLayout::CreatePanel(this);
    194   SetLayoutManager(layout);
    195 
    196   const int single_column_layout_id = 0;
    197   views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
    198   column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
    199                         GridLayout::USE_PREF, 0, 0);
    200 
    201   const int single_column_with_padding_layout_id = 1;
    202   views::ColumnSet* column_set_with_padding = layout->AddColumnSet(
    203       single_column_with_padding_layout_id);
    204   column_set_with_padding->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
    205                                      GridLayout::USE_PREF, 0, 0);
    206   column_set_with_padding->AddPaddingColumn(0, 2);
    207 
    208   layout->StartRow(0, single_column_layout_id);
    209   views::TabbedPane* tabbed_pane = new views::TabbedPane();
    210   layout->AddView(tabbed_pane);
    211   // NOTE: the panes need to be added after the tabbed_pane has been added to
    212   // its parent.
    213   std::wstring label_allowed = UTF16ToWide(l10n_util::GetStringUTF16(
    214       IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_TAB_LABEL));
    215   std::wstring label_blocked = UTF16ToWide(l10n_util::GetStringUTF16(
    216       IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_TAB_LABEL));
    217   tabbed_pane->AddTab(label_allowed, CreateAllowedPane());
    218   tabbed_pane->AddTab(label_blocked, CreateBlockedPane());
    219   tabbed_pane->SelectTabAt(0);
    220   tabbed_pane->set_listener(this);
    221   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    222 
    223   layout->StartRow(0, single_column_with_padding_layout_id);
    224   cookie_info_view_ = new CookieInfoView(false);
    225   layout->AddView(cookie_info_view_);
    226   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    227 
    228   layout->StartRow(0, single_column_with_padding_layout_id);
    229   infobar_ = new InfobarView();
    230   layout->AddView(infobar_);
    231 
    232   EnableControls();
    233   ShowCookieInfo();
    234 }
    235 
    236 views::View* CollectedCookiesWin::CreateAllowedPane() {
    237   TabSpecificContentSettings* content_settings =
    238       tab_contents_->GetTabSpecificContentSettings();
    239 
    240   // Create the controls that go into the pane.
    241   allowed_label_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16(
    242       IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL)));
    243   allowed_cookies_tree_model_.reset(
    244       content_settings->GetAllowedCookiesTreeModel());
    245   allowed_cookies_tree_ = new views::TreeView();
    246   allowed_cookies_tree_->SetModel(allowed_cookies_tree_model_.get());
    247   allowed_cookies_tree_->SetController(this);
    248   allowed_cookies_tree_->SetRootShown(false);
    249   allowed_cookies_tree_->SetEditable(false);
    250   allowed_cookies_tree_->set_lines_at_root(true);
    251   allowed_cookies_tree_->set_auto_expand_children(true);
    252 
    253   block_allowed_button_ = new views::NativeButton(this, UTF16ToWide(
    254       l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_BLOCK_BUTTON)));
    255 
    256   // Create the view that holds all the controls together.  This will be the
    257   // pane added to the tabbed pane.
    258   using views::GridLayout;
    259 
    260   views::View* pane = new views::View();
    261   GridLayout* layout = GridLayout::CreatePanel(pane);
    262   pane->SetLayoutManager(layout);
    263 
    264   const int single_column_layout_id = 0;
    265   views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
    266   column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
    267                         GridLayout::USE_PREF, 0, 0);
    268 
    269   layout->StartRow(0, single_column_layout_id);
    270   layout->AddView(allowed_label_);
    271   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    272 
    273   layout->StartRow(1, single_column_layout_id);
    274   layout->AddView(allowed_cookies_tree_, 1, 1, GridLayout::FILL,
    275                   GridLayout::FILL, kTreeViewWidth, kTreeViewHeight);
    276   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    277 
    278   layout->StartRow(0, single_column_layout_id);
    279   layout->AddView(block_allowed_button_, 1, 1, GridLayout::LEADING,
    280                   GridLayout::CENTER);
    281 
    282   return pane;
    283 }
    284 
    285 views::View* CollectedCookiesWin::CreateBlockedPane() {
    286   TabSpecificContentSettings* content_settings =
    287       tab_contents_->GetTabSpecificContentSettings();
    288 
    289   HostContentSettingsMap* host_content_settings_map =
    290       tab_contents_->profile()->GetHostContentSettingsMap();
    291 
    292   // Create the controls that go into the pane.
    293   blocked_label_ = new views::Label(
    294       UTF16ToWide(l10n_util::GetStringUTF16(
    295           host_content_settings_map->BlockThirdPartyCookies() ?
    296               IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED :
    297               IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL)));
    298   blocked_label_->SetMultiLine(true);
    299   blocked_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    300   blocked_cookies_tree_model_.reset(
    301       content_settings->GetBlockedCookiesTreeModel());
    302   blocked_cookies_tree_ = new views::TreeView();
    303   blocked_cookies_tree_->SetModel(blocked_cookies_tree_model_.get());
    304   blocked_cookies_tree_->SetController(this);
    305   blocked_cookies_tree_->SetRootShown(false);
    306   blocked_cookies_tree_->SetEditable(false);
    307   blocked_cookies_tree_->set_lines_at_root(true);
    308   blocked_cookies_tree_->set_auto_expand_children(true);
    309 
    310   allow_blocked_button_ = new views::NativeButton(this, UTF16ToWide(
    311       l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_ALLOW_BUTTON)));
    312   for_session_blocked_button_ = new views::NativeButton(this, UTF16ToWide(
    313       l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON)));
    314 
    315   // Create the view that holds all the controls together.  This will be the
    316   // pane added to the tabbed pane.
    317   using views::GridLayout;
    318 
    319   views::View* pane = new views::View();
    320   GridLayout* layout = GridLayout::CreatePanel(pane);
    321   pane->SetLayoutManager(layout);
    322 
    323   const int single_column_layout_id = 0;
    324   views::ColumnSet* column_set = layout->AddColumnSet(single_column_layout_id);
    325   column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
    326                         GridLayout::USE_PREF, 0, 0);
    327 
    328   const int three_columns_layout_id = 1;
    329   column_set = layout->AddColumnSet(three_columns_layout_id);
    330   column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
    331                         GridLayout::USE_PREF, 0, 0);
    332   column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
    333   column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
    334                         GridLayout::USE_PREF, 0, 0);
    335 
    336   layout->StartRow(0, single_column_layout_id);
    337   layout->AddView(blocked_label_, 1, 1, GridLayout::FILL, GridLayout::FILL);
    338   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    339 
    340   layout->StartRow(1, single_column_layout_id);
    341   layout->AddView(
    342       blocked_cookies_tree_, 1, 1, GridLayout::FILL, GridLayout::FILL,
    343       kTreeViewWidth, kTreeViewHeight);
    344   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
    345 
    346   layout->StartRow(0, three_columns_layout_id);
    347   layout->AddView(allow_blocked_button_);
    348   layout->AddView(for_session_blocked_button_);
    349 
    350   return pane;
    351 }
    352 
    353 ///////////////////////////////////////////////////////////////////////////////
    354 // ConstrainedDialogDelegate implementation.
    355 
    356 std::wstring CollectedCookiesWin::GetWindowTitle() const {
    357   return UTF16ToWide(
    358       l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE));
    359 }
    360 
    361 int CollectedCookiesWin::GetDialogButtons() const {
    362   return MessageBoxFlags::DIALOGBUTTON_CANCEL;
    363 }
    364 
    365 std::wstring CollectedCookiesWin::GetDialogButtonLabel(
    366     MessageBoxFlags::DialogButton button) const {
    367   return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLOSE));
    368 }
    369 
    370 void CollectedCookiesWin::DeleteDelegate() {
    371   delete this;
    372 }
    373 
    374 bool CollectedCookiesWin::Cancel() {
    375   if (status_changed_) {
    376     tab_contents_->AddInfoBar(
    377         new CollectedCookiesInfoBarDelegate(tab_contents_));
    378   }
    379 
    380   return true;
    381 }
    382 
    383 views::View* CollectedCookiesWin::GetContentsView() {
    384   return this;
    385 }
    386 
    387 ///////////////////////////////////////////////////////////////////////////////
    388 // views::ButtonListener implementation.
    389 
    390 void CollectedCookiesWin::ButtonPressed(views::Button* sender,
    391                                         const views::Event& event) {
    392   if (sender == block_allowed_button_)
    393     AddContentException(allowed_cookies_tree_, CONTENT_SETTING_BLOCK);
    394   else if (sender == allow_blocked_button_)
    395     AddContentException(blocked_cookies_tree_, CONTENT_SETTING_ALLOW);
    396   else if (sender == for_session_blocked_button_)
    397     AddContentException(blocked_cookies_tree_, CONTENT_SETTING_SESSION_ONLY);
    398 }
    399 
    400 ///////////////////////////////////////////////////////////////////////////////
    401 // views::TabbedPaneListener implementation.
    402 
    403 void CollectedCookiesWin::TabSelectedAt(int index) {
    404   EnableControls();
    405   ShowCookieInfo();
    406 }
    407 
    408 ///////////////////////////////////////////////////////////////////////////////
    409 // views::TreeViewController implementation.
    410 
    411 void CollectedCookiesWin::OnTreeViewSelectionChanged(
    412     views::TreeView* tree_view) {
    413   EnableControls();
    414   ShowCookieInfo();
    415 }
    416 
    417 ///////////////////////////////////////////////////////////////////////////////
    418 // CollectedCookiesWin, private methods.
    419 
    420 void CollectedCookiesWin::EnableControls() {
    421   bool enable_allowed_buttons = false;
    422   ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode();
    423   if (node) {
    424     CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
    425     if (cookie_node->GetDetailedInfo().node_type ==
    426         CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
    427       enable_allowed_buttons = static_cast<CookieTreeOriginNode*>(
    428           cookie_node)->CanCreateContentException();
    429     }
    430   }
    431   block_allowed_button_->SetEnabled(enable_allowed_buttons);
    432 
    433   bool enable_blocked_buttons = false;
    434   node = blocked_cookies_tree_->GetSelectedNode();
    435   if (node) {
    436     CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
    437     if (cookie_node->GetDetailedInfo().node_type ==
    438         CookieTreeNode::DetailedInfo::TYPE_ORIGIN) {
    439       enable_blocked_buttons = static_cast<CookieTreeOriginNode*>(
    440           cookie_node)->CanCreateContentException();
    441     }
    442   }
    443   allow_blocked_button_->SetEnabled(enable_blocked_buttons);
    444   for_session_blocked_button_->SetEnabled(enable_blocked_buttons);
    445 }
    446 
    447 void CollectedCookiesWin::ShowCookieInfo() {
    448   ui::TreeModelNode* node = allowed_cookies_tree_->GetSelectedNode();
    449   if (!node)
    450     node = blocked_cookies_tree_->GetSelectedNode();
    451 
    452   if (node) {
    453     CookieTreeNode* cookie_node = static_cast<CookieTreeNode*>(node);
    454     const CookieTreeNode::DetailedInfo detailed_info =
    455         cookie_node->GetDetailedInfo();
    456 
    457     if (detailed_info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE) {
    458       CookieTreeCookieNode* cookie_info_node =
    459           static_cast<CookieTreeCookieNode*>(cookie_node);
    460       cookie_info_view_->SetCookie(detailed_info.cookie->Domain(),
    461                                    *detailed_info.cookie);
    462     } else {
    463       cookie_info_view_->ClearCookieDisplay();
    464     }
    465   } else {
    466     cookie_info_view_->ClearCookieDisplay();
    467   }
    468 }
    469 
    470 void CollectedCookiesWin::AddContentException(views::TreeView* tree_view,
    471                                               ContentSetting setting) {
    472   CookieTreeOriginNode* origin_node =
    473       static_cast<CookieTreeOriginNode*>(tree_view->GetSelectedNode());
    474   origin_node->CreateContentException(
    475       tab_contents_->profile()->GetHostContentSettingsMap(), setting);
    476   infobar_->UpdateVisibility(true, setting, origin_node->GetTitle());
    477   gfx::Rect bounds = GetWidget()->GetClientAreaScreenBounds();
    478   // WidgetWin::GetBounds returns the bounds relative to the parent window,
    479   // while WidgetWin::SetBounds wants screen coordinates. Do the translation
    480   // here until http://crbug.com/52851 is fixed.
    481   POINT topleft = {bounds.x(), bounds.y()};
    482   MapWindowPoints(HWND_DESKTOP, tab_contents_->GetNativeView(), &topleft, 1);
    483   gfx::Size size = GetRootView()->GetPreferredSize();
    484   bounds.SetRect(topleft.x, topleft.y, size.width(), size.height());
    485   GetWidget()->SetBounds(bounds);
    486   status_changed_ = true;
    487 }
    488 
    489 ///////////////////////////////////////////////////////////////////////////////
    490 // NotificationObserver implementation.
    491 
    492 void CollectedCookiesWin::Observe(NotificationType type,
    493                                    const NotificationSource& source,
    494                                    const NotificationDetails& details) {
    495   DCHECK(type == NotificationType::COLLECTED_COOKIES_SHOWN);
    496   DCHECK_EQ(Source<TabSpecificContentSettings>(source).ptr(),
    497             tab_contents_->GetTabSpecificContentSettings());
    498   window_->CloseConstrainedWindow();
    499 }
    500