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