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.
ShowCollectedCookiesDialog(gfx::NativeWindow parent_window,TabContents * tab_contents)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:
InfobarView()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 }
~InfobarView()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.
UpdateVisibility(bool is_visible,ContentSetting setting,const std::wstring & domain_name)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.
Init()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.
GetPreferredSize()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
Layout()137 virtual void Layout() {
138 content_->SetBounds(
139 0, views::kRelatedControlVerticalSpacing,
140 width(), height() - views::kRelatedControlVerticalSpacing);
141 }
142
ViewHierarchyChanged(bool is_add,views::View * parent,views::View * child)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
CollectedCookiesWin(gfx::NativeWindow parent_window,TabContents * tab_contents)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
~CollectedCookiesWin()185 CollectedCookiesWin::~CollectedCookiesWin() {
186 allowed_cookies_tree_->SetModel(NULL);
187 blocked_cookies_tree_->SetModel(NULL);
188 }
189
Init()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
CreateAllowedPane()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
CreateBlockedPane()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
GetWindowTitle() const356 std::wstring CollectedCookiesWin::GetWindowTitle() const {
357 return UTF16ToWide(
358 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE));
359 }
360
GetDialogButtons() const361 int CollectedCookiesWin::GetDialogButtons() const {
362 return MessageBoxFlags::DIALOGBUTTON_CANCEL;
363 }
364
GetDialogButtonLabel(MessageBoxFlags::DialogButton button) const365 std::wstring CollectedCookiesWin::GetDialogButtonLabel(
366 MessageBoxFlags::DialogButton button) const {
367 return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLOSE));
368 }
369
DeleteDelegate()370 void CollectedCookiesWin::DeleteDelegate() {
371 delete this;
372 }
373
Cancel()374 bool CollectedCookiesWin::Cancel() {
375 if (status_changed_) {
376 tab_contents_->AddInfoBar(
377 new CollectedCookiesInfoBarDelegate(tab_contents_));
378 }
379
380 return true;
381 }
382
GetContentsView()383 views::View* CollectedCookiesWin::GetContentsView() {
384 return this;
385 }
386
387 ///////////////////////////////////////////////////////////////////////////////
388 // views::ButtonListener implementation.
389
ButtonPressed(views::Button * sender,const views::Event & event)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
TabSelectedAt(int index)403 void CollectedCookiesWin::TabSelectedAt(int index) {
404 EnableControls();
405 ShowCookieInfo();
406 }
407
408 ///////////////////////////////////////////////////////////////////////////////
409 // views::TreeViewController implementation.
410
OnTreeViewSelectionChanged(views::TreeView * tree_view)411 void CollectedCookiesWin::OnTreeViewSelectionChanged(
412 views::TreeView* tree_view) {
413 EnableControls();
414 ShowCookieInfo();
415 }
416
417 ///////////////////////////////////////////////////////////////////////////////
418 // CollectedCookiesWin, private methods.
419
EnableControls()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
ShowCookieInfo()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
AddContentException(views::TreeView * tree_view,ContentSetting setting)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
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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