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 32namespace browser { 33 34// Declared in browser_dialogs.h so others don't have to depend on our header. 35void 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 43namespace { 44// Spacing between the infobar frame and its contents. 45const int kInfobarVerticalPadding = 3; 46const int kInfobarHorizontalPadding = 8; 47 48// Width of the infobar frame. 49const int kInfobarBorderSize = 1; 50 51// Dimensions of the tree views. 52const int kTreeViewWidth = 400; 53const int kTreeViewHeight = 125; 54 55} // namespace 56 57// A custom view that conditionally displays an infobar. 58class 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 163CollectedCookiesWin::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 185CollectedCookiesWin::~CollectedCookiesWin() { 186 allowed_cookies_tree_->SetModel(NULL); 187 blocked_cookies_tree_->SetModel(NULL); 188} 189 190void 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 236views::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 285views::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 356std::wstring CollectedCookiesWin::GetWindowTitle() const { 357 return UTF16ToWide( 358 l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE)); 359} 360 361int CollectedCookiesWin::GetDialogButtons() const { 362 return MessageBoxFlags::DIALOGBUTTON_CANCEL; 363} 364 365std::wstring CollectedCookiesWin::GetDialogButtonLabel( 366 MessageBoxFlags::DialogButton button) const { 367 return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLOSE)); 368} 369 370void CollectedCookiesWin::DeleteDelegate() { 371 delete this; 372} 373 374bool CollectedCookiesWin::Cancel() { 375 if (status_changed_) { 376 tab_contents_->AddInfoBar( 377 new CollectedCookiesInfoBarDelegate(tab_contents_)); 378 } 379 380 return true; 381} 382 383views::View* CollectedCookiesWin::GetContentsView() { 384 return this; 385} 386 387/////////////////////////////////////////////////////////////////////////////// 388// views::ButtonListener implementation. 389 390void 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 403void CollectedCookiesWin::TabSelectedAt(int index) { 404 EnableControls(); 405 ShowCookieInfo(); 406} 407 408/////////////////////////////////////////////////////////////////////////////// 409// views::TreeViewController implementation. 410 411void CollectedCookiesWin::OnTreeViewSelectionChanged( 412 views::TreeView* tree_view) { 413 EnableControls(); 414 ShowCookieInfo(); 415} 416 417/////////////////////////////////////////////////////////////////////////////// 418// CollectedCookiesWin, private methods. 419 420void 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 447void 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 470void 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 492void 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