collected_cookies_gtk.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/gtk/collected_cookies_gtk.h" 6 7#include <string> 8 9#include "chrome/browser/cookies_tree_model.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/ui/gtk/gtk_util.h" 12#include "content/browser/tab_contents/tab_contents.h" 13#include "content/common/notification_source.h" 14#include "grit/generated_resources.h" 15#include "ui/base/l10n/l10n_util.h" 16 17namespace { 18// Width and height of the cookie tree view. 19const int kTreeViewWidth = 450; 20const int kTreeViewHeight = 150; 21 22// Padding within the banner box. 23const int kBannerPadding = 3; 24 25// Returns the text to display in the info bar when content settings were 26// created. 27const std::string GetInfobarLabel(ContentSetting setting, 28 bool multiple_domains_added, 29 const string16& domain_name) { 30 if (multiple_domains_added) { 31 switch (setting) { 32 case CONTENT_SETTING_BLOCK: 33 return l10n_util::GetStringUTF8( 34 IDS_COLLECTED_COOKIES_MULTIPLE_BLOCK_RULES_CREATED); 35 36 case CONTENT_SETTING_ALLOW: 37 return l10n_util::GetStringUTF8( 38 IDS_COLLECTED_COOKIES_MULTIPLE_ALLOW_RULES_CREATED); 39 40 case CONTENT_SETTING_SESSION_ONLY: 41 return l10n_util::GetStringUTF8( 42 IDS_COLLECTED_COOKIES_MULTIPLE_SESSION_RULES_CREATED); 43 44 default: 45 NOTREACHED(); 46 return std::string(); 47 } 48 } 49 50 switch (setting) { 51 case CONTENT_SETTING_BLOCK: 52 return l10n_util::GetStringFUTF8( 53 IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED, domain_name); 54 55 case CONTENT_SETTING_ALLOW: 56 return l10n_util::GetStringFUTF8( 57 IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED, domain_name); 58 59 case CONTENT_SETTING_SESSION_ONLY: 60 return l10n_util::GetStringFUTF8( 61 IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED, domain_name); 62 63 default: 64 NOTREACHED(); 65 return std::string(); 66 } 67} 68} // namespace 69 70CollectedCookiesGtk::CollectedCookiesGtk(GtkWindow* parent, 71 TabContents* tab_contents) 72 : tab_contents_(tab_contents) { 73 TabSpecificContentSettings* content_settings = 74 tab_contents->GetTabSpecificContentSettings(); 75 registrar_.Add(this, NotificationType::COLLECTED_COOKIES_SHOWN, 76 Source<TabSpecificContentSettings>(content_settings)); 77 78 Init(); 79} 80 81void CollectedCookiesGtk::Init() { 82 HostContentSettingsMap* host_content_settings_map = 83 tab_contents_->profile()->GetHostContentSettingsMap(); 84 85 dialog_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); 86 gtk_box_set_spacing(GTK_BOX(dialog_), gtk_util::kContentAreaSpacing); 87 88 GtkWidget* label = gtk_label_new( 89 l10n_util::GetStringUTF8(IDS_COLLECTED_COOKIES_DIALOG_TITLE).c_str()); 90 gtk_box_pack_start(GTK_BOX(dialog_), label, TRUE, TRUE, 0); 91 92 // Allowed Cookie list. 93 GtkWidget* cookie_list_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 94 gtk_box_pack_start(GTK_BOX(dialog_), cookie_list_vbox, TRUE, TRUE, 0); 95 96 label = gtk_label_new( 97 l10n_util::GetStringUTF8(IDS_COLLECTED_COOKIES_ALLOWED_COOKIES_LABEL). 98 c_str()); 99 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 100 gtk_box_pack_start(GTK_BOX(cookie_list_vbox), label, FALSE, FALSE, 0); 101 102 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL); 103 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), 104 GTK_POLICY_AUTOMATIC, 105 GTK_POLICY_AUTOMATIC); 106 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window), 107 GTK_SHADOW_ETCHED_IN); 108 gtk_box_pack_start(GTK_BOX(cookie_list_vbox), scroll_window, TRUE, TRUE, 0); 109 110 TabSpecificContentSettings* content_settings = 111 tab_contents_->GetTabSpecificContentSettings(); 112 113 allowed_cookies_tree_model_.reset( 114 content_settings->GetAllowedCookiesTreeModel()); 115 allowed_cookies_tree_adapter_.reset( 116 new gtk_tree::TreeAdapter(this, allowed_cookies_tree_model_.get())); 117 allowed_tree_ = gtk_tree_view_new_with_model( 118 GTK_TREE_MODEL(allowed_cookies_tree_adapter_->tree_store())); 119 gtk_widget_set_size_request(allowed_tree_, kTreeViewWidth, kTreeViewHeight); 120 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(allowed_tree_), FALSE); 121 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(allowed_tree_), TRUE); 122 gtk_container_add(GTK_CONTAINER(scroll_window), allowed_tree_); 123 124 GtkTreeViewColumn* title_column = gtk_tree_view_column_new(); 125 GtkCellRenderer* pixbuf_renderer = gtk_cell_renderer_pixbuf_new(); 126 gtk_tree_view_column_pack_start(title_column, pixbuf_renderer, FALSE); 127 gtk_tree_view_column_add_attribute(title_column, pixbuf_renderer, "pixbuf", 128 gtk_tree::TreeAdapter::COL_ICON); 129 GtkCellRenderer* title_renderer = gtk_cell_renderer_text_new(); 130 gtk_tree_view_column_pack_start(title_column, title_renderer, TRUE); 131 gtk_tree_view_column_add_attribute(title_column, title_renderer, "text", 132 gtk_tree::TreeAdapter::COL_TITLE); 133 gtk_tree_view_column_set_title( 134 title_column, l10n_util::GetStringUTF8( 135 IDS_COOKIES_DOMAIN_COLUMN_HEADER).c_str()); 136 gtk_tree_view_append_column(GTK_TREE_VIEW(allowed_tree_), title_column); 137 g_signal_connect(allowed_tree_, "row-expanded", 138 G_CALLBACK(OnTreeViewRowExpandedThunk), this); 139 allowed_selection_ = 140 gtk_tree_view_get_selection(GTK_TREE_VIEW(allowed_tree_)); 141 gtk_tree_selection_set_mode(allowed_selection_, GTK_SELECTION_MULTIPLE); 142 g_signal_connect(allowed_selection_, "changed", 143 G_CALLBACK(OnTreeViewSelectionChangeThunk), this); 144 145 GtkWidget* button_box = gtk_hbutton_box_new(); 146 gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_START); 147 gtk_box_set_spacing(GTK_BOX(button_box), gtk_util::kControlSpacing); 148 gtk_box_pack_start(GTK_BOX(dialog_), button_box, FALSE, FALSE, 0); 149 block_allowed_cookie_button_ = gtk_button_new_with_label( 150 l10n_util::GetStringUTF8(IDS_COLLECTED_COOKIES_BLOCK_BUTTON).c_str()); 151 g_signal_connect(block_allowed_cookie_button_, "clicked", 152 G_CALLBACK(OnBlockAllowedButtonClickedThunk), this); 153 gtk_container_add(GTK_CONTAINER(button_box), block_allowed_cookie_button_); 154 155 GtkWidget* separator = gtk_hseparator_new(); 156 gtk_box_pack_start(GTK_BOX(dialog_), separator, TRUE, TRUE, 0); 157 158 // Blocked Cookie list. 159 cookie_list_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 160 gtk_box_pack_start(GTK_BOX(dialog_), cookie_list_vbox, TRUE, TRUE, 0); 161 162 label = gtk_label_new( 163 l10n_util::GetStringUTF8( 164 host_content_settings_map->BlockThirdPartyCookies() ? 165 IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED : 166 IDS_COLLECTED_COOKIES_BLOCKED_COOKIES_LABEL).c_str()); 167 gtk_widget_set_size_request(label, kTreeViewWidth, -1); 168 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); 169 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); 170 gtk_box_pack_start(GTK_BOX(cookie_list_vbox), label, TRUE, TRUE, 0); 171 172 scroll_window = gtk_scrolled_window_new(NULL, NULL); 173 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), 174 GTK_POLICY_AUTOMATIC, 175 GTK_POLICY_AUTOMATIC); 176 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window), 177 GTK_SHADOW_ETCHED_IN); 178 gtk_box_pack_start(GTK_BOX(cookie_list_vbox), scroll_window, TRUE, TRUE, 0); 179 180 blocked_cookies_tree_model_.reset( 181 content_settings->GetBlockedCookiesTreeModel()); 182 blocked_cookies_tree_adapter_.reset( 183 new gtk_tree::TreeAdapter(this, blocked_cookies_tree_model_.get())); 184 blocked_tree_ = gtk_tree_view_new_with_model( 185 GTK_TREE_MODEL(blocked_cookies_tree_adapter_->tree_store())); 186 gtk_widget_set_size_request(blocked_tree_, kTreeViewWidth, kTreeViewHeight); 187 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(blocked_tree_), FALSE); 188 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(blocked_tree_), TRUE); 189 gtk_container_add(GTK_CONTAINER(scroll_window), blocked_tree_); 190 191 title_column = gtk_tree_view_column_new(); 192 pixbuf_renderer = gtk_cell_renderer_pixbuf_new(); 193 gtk_tree_view_column_pack_start(title_column, pixbuf_renderer, FALSE); 194 gtk_tree_view_column_add_attribute(title_column, pixbuf_renderer, "pixbuf", 195 gtk_tree::TreeAdapter::COL_ICON); 196 title_renderer = gtk_cell_renderer_text_new(); 197 gtk_tree_view_column_pack_start(title_column, title_renderer, TRUE); 198 gtk_tree_view_column_add_attribute(title_column, title_renderer, "text", 199 gtk_tree::TreeAdapter::COL_TITLE); 200 gtk_tree_view_column_set_title( 201 title_column, l10n_util::GetStringUTF8( 202 IDS_COOKIES_DOMAIN_COLUMN_HEADER).c_str()); 203 gtk_tree_view_append_column(GTK_TREE_VIEW(blocked_tree_), title_column); 204 g_signal_connect(blocked_tree_, "row-expanded", 205 G_CALLBACK(OnTreeViewRowExpandedThunk), this); 206 blocked_selection_ = 207 gtk_tree_view_get_selection(GTK_TREE_VIEW(blocked_tree_)); 208 gtk_tree_selection_set_mode(blocked_selection_, GTK_SELECTION_MULTIPLE); 209 g_signal_connect(blocked_selection_, "changed", 210 G_CALLBACK(OnTreeViewSelectionChangeThunk), this); 211 212 button_box = gtk_hbutton_box_new(); 213 gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_START); 214 gtk_box_set_spacing(GTK_BOX(button_box), gtk_util::kControlSpacing); 215 gtk_box_pack_start(GTK_BOX(dialog_), button_box, FALSE, FALSE, 0); 216 allow_blocked_cookie_button_ = gtk_button_new_with_label( 217 l10n_util::GetStringUTF8(IDS_COLLECTED_COOKIES_ALLOW_BUTTON).c_str()); 218 g_signal_connect(allow_blocked_cookie_button_, "clicked", 219 G_CALLBACK(OnAllowBlockedButtonClickedThunk), this); 220 gtk_container_add(GTK_CONTAINER(button_box), allow_blocked_cookie_button_); 221 for_session_blocked_cookie_button_ = gtk_button_new_with_label( 222 l10n_util::GetStringUTF8(IDS_COLLECTED_COOKIES_SESSION_ONLY_BUTTON). 223 c_str()); 224 g_signal_connect(for_session_blocked_cookie_button_, "clicked", 225 G_CALLBACK(OnForSessionBlockedButtonClickedThunk), this); 226 gtk_container_add(GTK_CONTAINER(button_box), 227 for_session_blocked_cookie_button_); 228 229 // Infobar. 230 infobar_ = gtk_frame_new(NULL); 231 GtkWidget* infobar_contents = gtk_hbox_new(FALSE, kBannerPadding); 232 gtk_container_set_border_width(GTK_CONTAINER(infobar_contents), 233 kBannerPadding); 234 gtk_container_add(GTK_CONTAINER(infobar_), infobar_contents); 235 GtkWidget* info_image = 236 gtk_image_new_from_stock(GTK_STOCK_DIALOG_INFO, 237 GTK_ICON_SIZE_SMALL_TOOLBAR); 238 gtk_box_pack_start(GTK_BOX(infobar_contents), info_image, FALSE, FALSE, 0); 239 infobar_label_ = gtk_label_new(NULL); 240 gtk_box_pack_start( 241 GTK_BOX(infobar_contents), infobar_label_, FALSE, FALSE, 0); 242 gtk_widget_show_all(infobar_); 243 gtk_widget_set_no_show_all(infobar_, TRUE); 244 gtk_widget_hide(infobar_); 245 gtk_box_pack_start(GTK_BOX(dialog_), infobar_, TRUE, TRUE, 0); 246 247 // Close button. 248 button_box = gtk_hbutton_box_new(); 249 gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END); 250 gtk_box_set_spacing(GTK_BOX(button_box), gtk_util::kControlSpacing); 251 gtk_box_pack_end(GTK_BOX(dialog_), button_box, FALSE, TRUE, 0); 252 close_button_ = gtk_button_new_from_stock(GTK_STOCK_CLOSE); 253 gtk_button_set_label(GTK_BUTTON(close_button_), 254 l10n_util::GetStringUTF8(IDS_CLOSE).c_str()); 255 g_signal_connect(close_button_, "clicked", G_CALLBACK(OnCloseThunk), this); 256 gtk_box_pack_end(GTK_BOX(button_box), close_button_, FALSE, TRUE, 0); 257 258 // Show the dialog. 259 allowed_cookies_tree_adapter_->Init(); 260 blocked_cookies_tree_adapter_->Init(); 261 EnableControls(); 262 window_ = tab_contents_->CreateConstrainedDialog(this); 263} 264 265CollectedCookiesGtk::~CollectedCookiesGtk() { 266 gtk_widget_destroy(dialog_); 267} 268 269GtkWidget* CollectedCookiesGtk::GetWidgetRoot() { 270 return dialog_; 271} 272 273GtkWidget* CollectedCookiesGtk::GetFocusWidget() { 274 return close_button_; 275} 276 277void CollectedCookiesGtk::DeleteDelegate() { 278 delete this; 279} 280 281bool CollectedCookiesGtk::SelectionContainsOriginNode( 282 GtkTreeSelection* selection, gtk_tree::TreeAdapter* adapter) { 283 // Check whether at least one "origin" node is selected. 284 GtkTreeModel* model; 285 GList* paths = 286 gtk_tree_selection_get_selected_rows(selection, &model); 287 bool contains_origin_node = false; 288 for (GList* item = paths; item; item = item->next) { 289 GtkTreeIter iter; 290 gtk_tree_model_get_iter( 291 model, &iter, reinterpret_cast<GtkTreePath*>(item->data)); 292 CookieTreeNode* node = 293 static_cast<CookieTreeNode*>(adapter->GetNode(&iter)); 294 if (node->GetDetailedInfo().node_type != 295 CookieTreeNode::DetailedInfo::TYPE_ORIGIN) 296 continue; 297 CookieTreeOriginNode* origin_node = static_cast<CookieTreeOriginNode*>( 298 node); 299 if (!origin_node->CanCreateContentException()) 300 continue; 301 contains_origin_node = true; 302 } 303 g_list_foreach(paths, reinterpret_cast<GFunc>(gtk_tree_path_free), NULL); 304 g_list_free(paths); 305 return contains_origin_node; 306} 307 308void CollectedCookiesGtk::EnableControls() { 309 // Update button states. 310 bool enable_for_allowed_cookies = 311 SelectionContainsOriginNode(allowed_selection_, 312 allowed_cookies_tree_adapter_.get()); 313 gtk_widget_set_sensitive(block_allowed_cookie_button_, 314 enable_for_allowed_cookies); 315 316 bool enable_for_blocked_cookies = 317 SelectionContainsOriginNode(blocked_selection_, 318 blocked_cookies_tree_adapter_.get()); 319 gtk_widget_set_sensitive(allow_blocked_cookie_button_, 320 enable_for_blocked_cookies); 321 gtk_widget_set_sensitive(for_session_blocked_cookie_button_, 322 enable_for_blocked_cookies); 323} 324 325void CollectedCookiesGtk::Observe(NotificationType type, 326 const NotificationSource& source, 327 const NotificationDetails& details) { 328 DCHECK(type == NotificationType::COLLECTED_COOKIES_SHOWN); 329 DCHECK_EQ(Source<TabSpecificContentSettings>(source).ptr(), 330 tab_contents_->GetTabSpecificContentSettings()); 331 window_->CloseConstrainedWindow(); 332} 333 334void CollectedCookiesGtk::OnClose(GtkWidget* close_button) { 335 window_->CloseConstrainedWindow(); 336} 337 338void CollectedCookiesGtk::AddExceptions(GtkTreeSelection* selection, 339 gtk_tree::TreeAdapter* adapter, 340 ContentSetting setting) { 341 GtkTreeModel* model; 342 GList* paths = 343 gtk_tree_selection_get_selected_rows(selection, &model); 344 string16 last_domain_name; 345 bool multiple_domains_added = false; 346 for (GList* item = paths; item; item = item->next) { 347 GtkTreeIter iter; 348 gtk_tree_model_get_iter( 349 model, &iter, reinterpret_cast<GtkTreePath*>(item->data)); 350 CookieTreeNode* node = 351 static_cast<CookieTreeNode*>(adapter->GetNode(&iter)); 352 if (node->GetDetailedInfo().node_type != 353 CookieTreeNode::DetailedInfo::TYPE_ORIGIN) 354 continue; 355 CookieTreeOriginNode* origin_node = static_cast<CookieTreeOriginNode*>( 356 node); 357 if (origin_node->CanCreateContentException()) { 358 if (!last_domain_name.empty()) 359 multiple_domains_added = true; 360 last_domain_name = origin_node->GetTitle(); 361 origin_node->CreateContentException( 362 tab_contents_->profile()->GetHostContentSettingsMap(), setting); 363 } 364 } 365 g_list_foreach(paths, reinterpret_cast<GFunc>(gtk_tree_path_free), NULL); 366 g_list_free(paths); 367 if (last_domain_name.empty()) { 368 gtk_widget_hide(infobar_); 369 } else { 370 gtk_label_set_text( 371 GTK_LABEL(infobar_label_), GetInfobarLabel( 372 setting, multiple_domains_added, last_domain_name).c_str()); 373 gtk_widget_show(infobar_); 374 } 375} 376 377void CollectedCookiesGtk::OnBlockAllowedButtonClicked(GtkWidget* button) { 378 AddExceptions(allowed_selection_, allowed_cookies_tree_adapter_.get(), 379 CONTENT_SETTING_BLOCK); 380} 381 382void CollectedCookiesGtk::OnAllowBlockedButtonClicked(GtkWidget* button) { 383 AddExceptions(blocked_selection_, blocked_cookies_tree_adapter_.get(), 384 CONTENT_SETTING_ALLOW); 385} 386 387void CollectedCookiesGtk::OnForSessionBlockedButtonClicked(GtkWidget* button) { 388 AddExceptions(blocked_selection_, blocked_cookies_tree_adapter_.get(), 389 CONTENT_SETTING_SESSION_ONLY); 390} 391 392void CollectedCookiesGtk::OnTreeViewRowExpanded(GtkWidget* tree_view, 393 GtkTreeIter* iter, 394 GtkTreePath* path) { 395 // When a row in the tree is expanded, expand all the children too. 396 g_signal_handlers_block_by_func( 397 tree_view, reinterpret_cast<gpointer>(OnTreeViewRowExpandedThunk), this); 398 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE); 399 g_signal_handlers_unblock_by_func( 400 tree_view, reinterpret_cast<gpointer>(OnTreeViewRowExpandedThunk), this); 401} 402 403void CollectedCookiesGtk::OnTreeViewSelectionChange(GtkWidget* selection) { 404 EnableControls(); 405} 406