- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / content_settings / collected_cookies_mac.mm
1 // Copyright (c) 2012 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 #import "chrome/browser/ui/cocoa/content_settings/collected_cookies_mac.h"
6
7 #include <vector>
8
9 #include "base/mac/bundle_locations.h"
10 #import "base/mac/mac_util.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
15 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
16 #include "chrome/browser/browsing_data/browsing_data_database_helper.h"
17 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
18 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
19 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
20 #include "chrome/browser/browsing_data/browsing_data_server_bound_cert_helper.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/content_settings/cookie_settings.h"
23 #include "chrome/browser/content_settings/local_shared_objects_container.h"
24 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
25 #include "chrome/browser/infobars/infobar_service.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/ui/browser_dialogs.h"
28 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
29 #import "chrome/browser/ui/cocoa/content_settings/cookie_details_view_controller.h"
30 #import "chrome/browser/ui/cocoa/vertical_gradient_view.h"
31 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h"
32 #include "chrome/common/pref_names.h"
33 #include "content/public/browser/notification_details.h"
34 #include "content/public/browser/notification_source.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/browser/web_contents_view.h"
37 #include "grit/generated_resources.h"
38 #include "grit/theme_resources.h"
39 #import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
40 #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
41 #include "third_party/apple_sample_code/ImageAndTextCell.h"
42 #include "ui/base/l10n/l10n_util_mac.h"
43 #include "ui/base/resource/resource_bundle.h"
44 #include "ui/gfx/image/image.h"
45 #include "ui/gfx/image/image_skia.h"
46 #include "ui/gfx/image/image_skia_util_mac.h"
47
48 namespace {
49 // Colors for the infobar.
50 const double kBannerGradientColorTop[3] =
51     {255.0 / 255.0, 242.0 / 255.0, 183.0 / 255.0};
52 const double kBannerGradientColorBottom[3] =
53     {250.0 / 255.0, 230.0 / 255.0, 145.0 / 255.0};
54 const double kBannerStrokeColor = 135.0 / 255.0;
55
56 enum TabViewItemIndices {
57   kAllowedCookiesTabIndex = 0,
58   kBlockedCookiesTabIndex
59 };
60
61 } // namespace
62
63 namespace chrome {
64
65 // Declared in browser_dialogs.h so others don't have to depend on our header.
66 void ShowCollectedCookiesDialog(content::WebContents* web_contents) {
67   // Deletes itself on close.
68   new CollectedCookiesMac(web_contents);
69 }
70
71 }  // namespace chrome
72
73 #pragma mark Constrained window delegate
74
75 CollectedCookiesMac::CollectedCookiesMac(content::WebContents* web_contents) {
76   TabSpecificContentSettings* content_settings =
77       TabSpecificContentSettings::FromWebContents(web_contents);
78   registrar_.Add(this, chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN,
79                  content::Source<TabSpecificContentSettings>(content_settings));
80
81   sheet_controller_.reset([[CollectedCookiesWindowController alloc]
82       initWithWebContents:web_contents
83       collectedCookiesMac:this]);
84
85   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
86       [[CustomConstrainedWindowSheet alloc]
87           initWithCustomWindow:[sheet_controller_ window]]);
88   window_.reset(new ConstrainedWindowMac(
89       this, web_contents, sheet));
90 }
91
92 CollectedCookiesMac::~CollectedCookiesMac() {
93 }
94
95 void CollectedCookiesMac::Observe(int type,
96                                   const content::NotificationSource& source,
97                                   const content::NotificationDetails& details) {
98   DCHECK(type == chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN);
99   window_->CloseWebContentsModalDialog();
100 }
101
102 void CollectedCookiesMac::PerformClose() {
103   window_->CloseWebContentsModalDialog();
104 }
105
106 void CollectedCookiesMac::OnConstrainedWindowClosed(
107     ConstrainedWindowMac* window) {
108   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
109 }
110
111 #pragma mark Window Controller
112
113 @interface CollectedCookiesWindowController(Private)
114 -(void)showInfoBarForDomain:(const string16&)domain
115                     setting:(ContentSetting)setting;
116 -(void)showInfoBarForMultipleDomainsAndSetting:(ContentSetting)setting;
117 -(void)animateInfoBar;
118 @end
119
120 @implementation CollectedCookiesWindowController
121
122 @synthesize allowedCookiesButtonsEnabled =
123     allowedCookiesButtonsEnabled_;
124 @synthesize blockedCookiesButtonsEnabled =
125     blockedCookiesButtonsEnabled_;
126
127 @synthesize allowedTreeController = allowedTreeController_;
128 @synthesize blockedTreeController = blockedTreeController_;
129 @synthesize allowedOutlineView = allowedOutlineView_;
130 @synthesize blockedOutlineView = blockedOutlineView_;
131 @synthesize infoBar = infoBar_;
132 @synthesize infoBarIcon = infoBarIcon_;
133 @synthesize infoBarText = infoBarText_;
134 @synthesize tabView = tabView_;
135 @synthesize blockedScrollView = blockedScrollView_;
136 @synthesize blockedCookiesText = blockedCookiesText_;
137 @synthesize cookieDetailsViewPlaceholder = cookieDetailsViewPlaceholder_;
138
139 - (id)initWithWebContents:(content::WebContents*)webContents
140       collectedCookiesMac:(CollectedCookiesMac*)collectedCookiesMac {
141   DCHECK(webContents);
142
143   NSString* nibpath =
144       [base::mac::FrameworkBundle() pathForResource:@"CollectedCookies"
145                                              ofType:@"nib"];
146   if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
147     webContents_ = webContents;
148     collectedCookiesMac_ = collectedCookiesMac;
149     [self loadTreeModelFromWebContents];
150
151     animation_.reset([[NSViewAnimation alloc] init]);
152     [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
153   }
154   return self;
155 }
156
157 - (void)awakeFromNib {
158   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
159   NSImage* infoIcon = rb.GetNativeImageNamed(IDR_INFO).ToNSImage();
160   [infoBarIcon_ setImage:infoIcon];
161
162   // Initialize the banner gradient and stroke color.
163   NSColor* bannerStartingColor =
164       [NSColor colorWithCalibratedRed:kBannerGradientColorTop[0]
165                                 green:kBannerGradientColorTop[1]
166                                  blue:kBannerGradientColorTop[2]
167                                 alpha:1.0];
168   NSColor* bannerEndingColor =
169       [NSColor colorWithCalibratedRed:kBannerGradientColorBottom[0]
170                                 green:kBannerGradientColorBottom[1]
171                                  blue:kBannerGradientColorBottom[2]
172                                 alpha:1.0];
173   base::scoped_nsobject<NSGradient> bannerGradient(
174       [[NSGradient alloc] initWithStartingColor:bannerStartingColor
175                                     endingColor:bannerEndingColor]);
176   [infoBar_ setGradient:bannerGradient];
177
178   NSColor* bannerStrokeColor =
179       [NSColor colorWithCalibratedWhite:kBannerStrokeColor
180                                   alpha:1.0];
181   [infoBar_ setStrokeColor:bannerStrokeColor];
182
183   // Change the label of the blocked cookies part if necessary.
184   Profile* profile =
185       Profile::FromBrowserContext(webContents_->GetBrowserContext());
186   if (profile->GetPrefs()->GetBoolean(prefs::kBlockThirdPartyCookies)) {
187     [blockedCookiesText_ setStringValue:l10n_util::GetNSString(
188         IDS_COLLECTED_COOKIES_BLOCKED_THIRD_PARTY_BLOCKING_ENABLED)];
189     CGFloat textDeltaY = [GTMUILocalizerAndLayoutTweaker
190         sizeToFitFixedWidthTextField:blockedCookiesText_];
191
192     // Shrink the blocked cookies outline view.
193     NSRect frame = [blockedScrollView_ frame];
194     frame.size.height -= textDeltaY;
195     [blockedScrollView_ setFrame:frame];
196
197     // Move the label down so it actually fits.
198     frame = [blockedCookiesText_ frame];
199     frame.origin.y -= textDeltaY;
200     [blockedCookiesText_ setFrame:frame];
201   }
202
203   detailsViewController_.reset([[CookieDetailsViewController alloc] init]);
204
205   NSView* detailView = [detailsViewController_.get() view];
206   NSRect viewFrameRect = [cookieDetailsViewPlaceholder_ frame];
207   [[detailsViewController_.get() view] setFrame:viewFrameRect];
208   [[cookieDetailsViewPlaceholder_ superview]
209       replaceSubview:cookieDetailsViewPlaceholder_
210                 with:detailView];
211
212   [self tabView:tabView_ didSelectTabViewItem:[tabView_ selectedTabViewItem]];
213 }
214
215 - (void)windowWillClose:(NSNotification*)notif {
216   if (contentSettingsChanged_) {
217     CollectedCookiesInfoBarDelegate::Create(
218         InfoBarService::FromWebContents(webContents_));
219   }
220   [allowedOutlineView_ setDelegate:nil];
221   [blockedOutlineView_ setDelegate:nil];
222   [animation_ stopAnimation];
223 }
224
225 - (IBAction)closeSheet:(id)sender {
226   collectedCookiesMac_->PerformClose();
227 }
228
229 - (void)addException:(ContentSetting)setting
230    forTreeController:(NSTreeController*)controller {
231   NSArray* nodes = [controller selectedNodes];
232   BOOL multipleDomainsChanged = NO;
233   string16 lastDomain;
234   for (NSTreeNode* treeNode in nodes) {
235     CocoaCookieTreeNode* node = [treeNode representedObject];
236     CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
237     if (cookie->GetDetailedInfo().node_type !=
238         CookieTreeNode::DetailedInfo::TYPE_HOST) {
239       continue;
240     }
241     Profile* profile =
242         Profile::FromBrowserContext(webContents_->GetBrowserContext());
243     CookieTreeHostNode* host_node =
244         static_cast<CookieTreeHostNode*>(cookie);
245     host_node->CreateContentException(
246         CookieSettings::Factory::GetForProfile(profile).get(), setting);
247     if (!lastDomain.empty())
248       multipleDomainsChanged = YES;
249     lastDomain = host_node->GetTitle();
250   }
251   if (multipleDomainsChanged)
252     [self showInfoBarForMultipleDomainsAndSetting:setting];
253   else
254     [self showInfoBarForDomain:lastDomain setting:setting];
255   contentSettingsChanged_ = YES;
256 }
257
258 - (IBAction)allowOrigin:(id)sender {
259   [self    addException:CONTENT_SETTING_ALLOW
260       forTreeController:blockedTreeController_];
261 }
262
263 - (IBAction)allowForSessionFromOrigin:(id)sender {
264   [self    addException:CONTENT_SETTING_SESSION_ONLY
265       forTreeController:blockedTreeController_];
266 }
267
268 - (IBAction)blockOrigin:(id)sender {
269   [self    addException:CONTENT_SETTING_BLOCK
270       forTreeController:allowedTreeController_];
271 }
272
273 - (CocoaCookieTreeNode*)cocoaAllowedTreeModel {
274   return cocoaAllowedTreeModel_.get();
275 }
276 - (void)setCocoaAllowedTreeModel:(CocoaCookieTreeNode*)model {
277   cocoaAllowedTreeModel_.reset([model retain]);
278 }
279
280 - (CookiesTreeModel*)allowedTreeModel {
281   return allowedTreeModel_.get();
282 }
283
284 - (CocoaCookieTreeNode*)cocoaBlockedTreeModel {
285   return cocoaBlockedTreeModel_.get();
286 }
287 - (void)setCocoaBlockedTreeModel:(CocoaCookieTreeNode*)model {
288   cocoaBlockedTreeModel_.reset([model retain]);
289 }
290
291 - (CookiesTreeModel*)blockedTreeModel {
292   return blockedTreeModel_.get();
293 }
294
295 - (void)outlineView:(NSOutlineView*)outlineView
296     willDisplayCell:(id)cell
297      forTableColumn:(NSTableColumn*)tableColumn
298                item:(id)item {
299   CocoaCookieTreeNode* node = [item representedObject];
300   int index;
301   if (outlineView == allowedOutlineView_)
302     index = allowedTreeModel_->GetIconIndex([node treeNode]);
303   else
304     index = blockedTreeModel_->GetIconIndex([node treeNode]);
305   NSImage* icon = nil;
306   if (index >= 0)
307     icon = [icons_ objectAtIndex:index];
308   else
309     icon = [icons_ lastObject];
310   DCHECK([cell isKindOfClass:[ImageAndTextCell class]]);
311   [static_cast<ImageAndTextCell*>(cell) setImage:icon];
312 }
313
314 - (void)outlineViewSelectionDidChange:(NSNotification*)notif {
315   BOOL isAllowedOutlineView;
316   if ([notif object] == allowedOutlineView_) {
317     isAllowedOutlineView = YES;
318   } else if ([notif object] == blockedOutlineView_) {
319     isAllowedOutlineView = NO;
320   } else {
321     NOTREACHED();
322     return;
323   }
324   NSTreeController* controller =
325       isAllowedOutlineView ? allowedTreeController_ : blockedTreeController_;
326
327   NSArray* nodes = [controller selectedNodes];
328   for (NSTreeNode* treeNode in nodes) {
329     CocoaCookieTreeNode* node = [treeNode representedObject];
330     CookieTreeNode* cookie = static_cast<CookieTreeNode*>([node treeNode]);
331     if (cookie->GetDetailedInfo().node_type !=
332         CookieTreeNode::DetailedInfo::TYPE_HOST) {
333       continue;
334     }
335    CookieTreeHostNode* host_node =
336        static_cast<CookieTreeHostNode*>(cookie);
337    if (host_node->CanCreateContentException()) {
338       if (isAllowedOutlineView) {
339         [self setAllowedCookiesButtonsEnabled:YES];
340       } else {
341         [self setBlockedCookiesButtonsEnabled:YES];
342       }
343       return;
344     }
345   }
346   if (isAllowedOutlineView) {
347     [self setAllowedCookiesButtonsEnabled:NO];
348   } else {
349     [self setBlockedCookiesButtonsEnabled:NO];
350   }
351 }
352
353 // Initializes the |allowedTreeModel_| and |blockedTreeModel_|, and builds
354 // the |cocoaAllowedTreeModel_| and |cocoaBlockedTreeModel_|.
355 - (void)loadTreeModelFromWebContents {
356   TabSpecificContentSettings* content_settings =
357       TabSpecificContentSettings::FromWebContents(webContents_);
358
359   const LocalSharedObjectsContainer& allowed_data =
360       content_settings->allowed_local_shared_objects();
361   allowedTreeModel_ = allowed_data.CreateCookiesTreeModel();
362
363   const LocalSharedObjectsContainer& blocked_data =
364       content_settings->blocked_local_shared_objects();
365   blockedTreeModel_ = blocked_data.CreateCookiesTreeModel();
366
367   // Convert the model's icons from Skia to Cocoa.
368   std::vector<gfx::ImageSkia> skiaIcons;
369   allowedTreeModel_->GetIcons(&skiaIcons);
370   icons_.reset([[NSMutableArray alloc] init]);
371   for (std::vector<gfx::ImageSkia>::iterator it = skiaIcons.begin();
372        it != skiaIcons.end(); ++it) {
373     [icons_ addObject:gfx::NSImageFromImageSkia(*it)];
374   }
375
376   // Default icon will be the last item in the array.
377   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
378   // TODO(rsesek): Rename this resource now that it's in multiple places.
379   [icons_ addObject:
380       rb.GetNativeImageNamed(IDR_BOOKMARK_BAR_FOLDER).ToNSImage()];
381
382   // Create the Cocoa model.
383   CookieTreeNode* root =
384       static_cast<CookieTreeNode*>(allowedTreeModel_->GetRoot());
385   base::scoped_nsobject<CocoaCookieTreeNode> model(
386       [[CocoaCookieTreeNode alloc] initWithNode:root]);
387   [self setCocoaAllowedTreeModel:model.get()];  // Takes ownership.
388   root = static_cast<CookieTreeNode*>(blockedTreeModel_->GetRoot());
389   model.reset(
390       [[CocoaCookieTreeNode alloc] initWithNode:root]);
391   [self setCocoaBlockedTreeModel:model.get()];  // Takes ownership.
392 }
393
394 -(void)showInfoBarForMultipleDomainsAndSetting:(ContentSetting)setting {
395   NSString* label;
396   switch (setting) {
397     case CONTENT_SETTING_BLOCK:
398       label = l10n_util::GetNSString(
399           IDS_COLLECTED_COOKIES_MULTIPLE_BLOCK_RULES_CREATED);
400       break;
401
402     case CONTENT_SETTING_ALLOW:
403       label = l10n_util::GetNSString(
404           IDS_COLLECTED_COOKIES_MULTIPLE_ALLOW_RULES_CREATED);
405       break;
406
407     case CONTENT_SETTING_SESSION_ONLY:
408       label = l10n_util::GetNSString(
409           IDS_COLLECTED_COOKIES_MULTIPLE_SESSION_RULES_CREATED);
410       break;
411
412     default:
413       NOTREACHED();
414       label = [[[NSString alloc] init] autorelease];
415   }
416   [infoBarText_ setStringValue:label];
417   [self animateInfoBar];
418 }
419
420 -(void)showInfoBarForDomain:(const string16&)domain
421                     setting:(ContentSetting)setting {
422   NSString* label;
423   switch (setting) {
424     case CONTENT_SETTING_BLOCK:
425       label = l10n_util::GetNSStringF(
426           IDS_COLLECTED_COOKIES_BLOCK_RULE_CREATED,
427           domain);
428       break;
429
430     case CONTENT_SETTING_ALLOW:
431       label = l10n_util::GetNSStringF(
432           IDS_COLLECTED_COOKIES_ALLOW_RULE_CREATED,
433           domain);
434       break;
435
436     case CONTENT_SETTING_SESSION_ONLY:
437       label = l10n_util::GetNSStringF(
438           IDS_COLLECTED_COOKIES_SESSION_RULE_CREATED,
439           domain);
440       break;
441
442     default:
443       NOTREACHED();
444       label = [[[NSString alloc] init] autorelease];
445   }
446   [infoBarText_ setStringValue:label];
447   [self animateInfoBar];
448 }
449
450 -(void)animateInfoBar {
451   if (infoBarVisible_)
452     return;
453
454   infoBarVisible_ = YES;
455
456   NSMutableArray* animations = [NSMutableArray arrayWithCapacity:3];
457
458   NSWindow* sheet = [self window];
459   NSRect sheetFrame = [sheet frame];
460   NSRect infoBarFrame = [infoBar_ frame];
461   NSRect tabViewFrame = [tabView_ frame];
462
463   // Calculate the end position of the info bar and set it to its start
464   // position.
465   infoBarFrame.origin.y = NSHeight(sheetFrame);
466   infoBarFrame.size.width = NSWidth(sheetFrame);
467   [infoBar_ setFrame:infoBarFrame];
468   [[[self window] contentView] addSubview:infoBar_];
469
470   // Calculate the new position of the sheet.
471   sheetFrame.origin.y -= NSHeight(infoBarFrame);
472   sheetFrame.size.height += NSHeight(infoBarFrame);
473
474   // Slide the infobar in.
475   [animations addObject:
476       [NSDictionary dictionaryWithObjectsAndKeys:
477           infoBar_, NSViewAnimationTargetKey,
478           [NSValue valueWithRect:infoBarFrame],
479               NSViewAnimationEndFrameKey,
480           nil]];
481   // Make sure the tab view ends up in the right position.
482   [animations addObject:
483       [NSDictionary dictionaryWithObjectsAndKeys:
484           tabView_, NSViewAnimationTargetKey,
485           [NSValue valueWithRect:tabViewFrame],
486               NSViewAnimationEndFrameKey,
487           nil]];
488
489   // Grow the sheet.
490   [animations addObject:
491       [NSDictionary dictionaryWithObjectsAndKeys:
492           sheet, NSViewAnimationTargetKey,
493           [NSValue valueWithRect:sheetFrame],
494               NSViewAnimationEndFrameKey,
495           nil]];
496   [animation_ setViewAnimations:animations];
497   // The default duration is 0.5s, which actually feels slow in here, so speed
498   // it up a bit.
499   [animation_ gtm_setDuration:0.2
500                     eventMask:NSLeftMouseUpMask];
501   [animation_ startAnimation];
502 }
503
504 - (void)         tabView:(NSTabView*)tabView
505     didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
506   NSTreeController* treeController = nil;
507   switch ([tabView indexOfTabViewItem:tabViewItem]) {
508     case kAllowedCookiesTabIndex:
509       treeController = allowedTreeController_;
510       break;
511     case kBlockedCookiesTabIndex:
512       treeController = blockedTreeController_;
513       break;
514     default:
515       NOTREACHED();
516       return;
517   }
518   [detailsViewController_ configureBindingsForTreeController:treeController];
519 }
520
521 @end