summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-01 15:50:51 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-01 15:50:51 +0000
commitdd716ab80774cba276e8b5eb61041f9497ddf642 (patch)
tree1e408f488b0a8b2fb8f38481e042f1f6db12e658 /chrome/browser/cocoa
parent31a9bdff16526415c4c00aba0cb41cc6654d3e69 (diff)
downloadchromium_src-dd716ab80774cba276e8b5eb61041f9497ddf642.zip
chromium_src-dd716ab80774cba276e8b5eb61041f9497ddf642.tar.gz
chromium_src-dd716ab80774cba276e8b5eb61041f9497ddf642.tar.bz2
First cut at popup blocking for Mac. Remove ifdefs in cross-platform code. Implement displaying of notification, menu of popups still to come.
BUG=13160 TEST=popup notification should display and popups blocked accordingly. Can close notification widget to prevent more notifications for this tab. Review URL: http://codereview.chromium.org/150132 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19735 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/blocked_popup_container_controller.h52
-rw-r--r--chrome/browser/cocoa/blocked_popup_container_controller.mm216
-rw-r--r--chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm85
3 files changed, 353 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/blocked_popup_container_controller.h b/chrome/browser/cocoa/blocked_popup_container_controller.h
new file mode 100644
index 0000000..39cba6f
--- /dev/null
+++ b/chrome/browser/cocoa/blocked_popup_container_controller.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_CONTROLLER_H_
+#define CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_CONTROLLER_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/blocked_popup_container.h"
+
+// Controller for the blocked popup view. Communicates with the cross-platform
+// code via a C++ bridge class, below. The BlockedPopupContainer class doesn't
+// really "own" the bridge, it just keeps a pointer to it and calls Destroy() on
+// it when it's supposed to go away. As a result, this class needs to own itself
+// (always keep an extra retain), and will autorelease itself (and the bridge
+// which it owns) when the bridge gets a Destroy() message.
+// TODO(pinkerton): Reverse the ownership if it makes more sense. I'm leaving
+// it this way because I assume we eventually want this to be a
+// NSViewController, and we usually have the Obj-C controller owning the
+// bridge (rather than the other way around).
+@interface BlockedPopupContainerController : NSObject {
+ @private
+ scoped_ptr<BlockedPopupContainerView> bridge_;
+ BlockedPopupContainer* container_; // Weak. "owns" me.
+ scoped_nsobject<NSView> view_;
+ IBOutlet NSTextField* label_;
+}
+
+// Initialize with the given popup container. Creates the C++ bridge object
+// used to represet the "view".
+- (id)initWithContainer:(BlockedPopupContainer*)container;
+
+// Returns the C++ brige object.
+- (BlockedPopupContainerView*)bridge;
+
+// Called by the bridge to perform certain actions from the back-end code.
+- (void)show;
+- (void)hide;
+- (void)update;
+
+@end
+
+@interface BlockedPopupContainerController(ForTesting)
+- (NSView*)view;
+- (NSView*)label;
+- (IBAction)closePopup:(id)sender;
+@end
+
+#endif // CHROME_BROWSER_VIEWS_BLOCKED_POPUP_CONTAINER_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/blocked_popup_container_controller.mm b/chrome/browser/cocoa/blocked_popup_container_controller.mm
new file mode 100644
index 0000000..93c3e49
--- /dev/null
+++ b/chrome/browser/cocoa/blocked_popup_container_controller.mm
@@ -0,0 +1,216 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#import "chrome/browser/cocoa/blocked_popup_container_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "grit/generated_resources.h"
+
+#import "chrome/browser/cocoa/background_gradient_view.h"
+
+// A C++ bridge class that manages the interaction between the C++ interface
+// and the Objective-C view controller that implements the popup blocker.
+class BlockedPopupContainerViewBridge : public BlockedPopupContainerView {
+ public:
+ BlockedPopupContainerViewBridge(BlockedPopupContainerController* controller);
+ virtual ~BlockedPopupContainerViewBridge();
+
+ // Overrides from BlockedPopupContainerView
+ virtual void SetPosition();
+ virtual void ShowView();
+ virtual void UpdateLabel();
+ virtual void HideView();
+ virtual void Destroy();
+
+ private:
+ BlockedPopupContainerController* controller_; // Weak, owns us.
+};
+
+@interface BlockedPopupContainerController(Private)
+- (void)initPopupView;
+- (NSView*)containingView;
+@end
+
+@implementation BlockedPopupContainerController
+
+// Initialize with the given popup container. Creates the C++ bridge object
+// used to represent the "view".
+- (id)initWithContainer:(BlockedPopupContainer*)container {
+ if ((self = [super init])) {
+ container_ = container;
+ bridge_.reset(new BlockedPopupContainerViewBridge(self));
+ [self initPopupView];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [view_ removeFromSuperview];
+ [super dealloc];
+}
+
+- (IBAction)closePopup:(id)sender {
+ container_->set_dismissed();
+ container_->CloseAll();
+}
+
+// Create and initialize the popup view and its label, close box, etc.
+- (void)initPopupView {
+ static const float kWidth = 200.0;
+ static const float kHeight = 20.0;
+ static const float kCloseBoxSize = 16.0;
+ static const float kCloseBoxPaddingY = 2.0;
+ static const float kLabelPaddingX = 5.0;
+
+ // Create it below the parent's bottom edge so we can animate it into place.
+ NSRect startFrame = NSMakeRect(0.0, -kHeight, kWidth, kHeight);
+ view_.reset([[BackgroundGradientView alloc] initWithFrame:startFrame]);
+ [view_ setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
+
+ // Create the text label and position it. We'll resize it later when the
+ // label gets updated. The view owns the label, we only hold a weak reference.
+ NSRect labelFrame = NSMakeRect(kLabelPaddingX,
+ 0,
+ startFrame.size.width - kCloseBoxSize,
+ startFrame.size.height);
+ label_ = [[[NSTextField alloc] initWithFrame:labelFrame] autorelease];
+ [label_ setSelectable:NO];
+ [label_ setAutoresizingMask:NSViewWidthSizable];
+ [label_ setBordered:NO];
+ [label_ setBezeled:NO];
+ [label_ setDrawsBackground:NO];
+ [view_ addSubview:label_];
+
+ // Create the close box and position at the left of the view.
+ NSRect closeFrame = NSMakeRect(startFrame.size.width - kCloseBoxSize,
+ kCloseBoxPaddingY,
+ kCloseBoxSize,
+ kCloseBoxSize);
+ NSButton* close = [[[NSButton alloc] initWithFrame:closeFrame] autorelease];
+ [close setAutoresizingMask:NSViewMinXMargin];
+ [close setImage:[NSImage imageNamed:@"close_bar"]];
+ [close setAlternateImage:[NSImage imageNamed:@"close_bar_p"]];
+ [close setBordered:NO];
+ [close setTarget:self];
+ [close setAction:@selector(closePopup:)];
+ [view_ addSubview:close];
+}
+
+// Returns the C++ brige object.
+- (BlockedPopupContainerView*)bridge {
+ return bridge_.get();
+}
+
+// Returns the parent of the RWHVMac. We insert our popup blocker as a sibling
+// so that it stays around as the RWHVMac is created/destroyed during
+// navigation.
+- (NSView*)containingView {
+ return container_->GetConstrainingContents(NULL)->view()->GetNativeView();
+}
+
+- (void)show {
+ const float kLeftPadding = 20; // Leave room for the scrollbar.
+
+ // No need to do anything if it's already on screen.
+ if ([view_ superview]) return;
+
+ // Position the view at the bottom right corner, always leaving room for the
+ // scrollbar. This is what window does. It also doesn't care about covering
+ // up the horizontal scrollbar.
+ NSView* parent = [self containingView];
+ NSRect frame = [view_ frame];
+ frame.origin.x = [parent frame].size.width - frame.size.width - kLeftPadding;
+ [view_ setFrame:frame];
+
+ // Add the view and animate it sliding up into view.
+ [parent addSubview:view_.get()];
+ frame.origin.y = 0;
+ [[view_ animator] setFrame:frame];
+}
+
+- (void)hide {
+ [view_ removeFromSuperview];
+}
+
+// Resize the view based on the new label contents. The autoresize mask will
+// take care of resizing everything else.
+- (void)resizeWithLabel:(NSString*)label {
+#if 0
+// TODO(pinkerton): fix this once the popup gets put in.
+ NSSize stringSize = [label sizeWithAttributes:nil];
+ NSRect frame = [view_ frame];
+ float originalWidth = frame.size.width;
+ frame.size.width = stringSize.width + 16 + 5;
+ frame.origin.x -= frame.size.width - originalWidth;
+ [view_ setFrame:frame];
+#endif
+}
+
+- (void)update {
+ size_t blockedPopups = container_->GetBlockedPopupCount();
+ NSString* label = nil;
+ if (blockedPopups) {
+ label = base::SysUTF16ToNSString(
+ l10n_util::GetStringFUTF16(IDS_POPUPS_BLOCKED_COUNT,
+ UintToString16(blockedPopups)));
+ } else {
+ label = base::SysUTF16ToNSString(
+ l10n_util::GetStringUTF16(IDS_POPUPS_UNBLOCKED));
+ }
+ [self resizeWithLabel:label];
+ [label_ setStringValue:label];
+}
+
+- (NSView*)view {
+ return view_.get();
+}
+
+- (NSView*)label {
+ return label_;
+}
+
+@end
+
+//---------------------------------------------------------------------------
+
+BlockedPopupContainerView* BlockedPopupContainerView::Create(
+ BlockedPopupContainer* container) {
+ // We "leak" |blocker| for now, we'll release it when the bridge class
+ // gets a Destroy() message.
+ BlockedPopupContainerController* blocker =
+ [[BlockedPopupContainerController alloc] initWithContainer:container];
+ return [blocker bridge];
+}
+
+BlockedPopupContainerViewBridge::BlockedPopupContainerViewBridge(
+ BlockedPopupContainerController* controller) {
+ controller_ = controller;
+}
+
+BlockedPopupContainerViewBridge::~BlockedPopupContainerViewBridge() {
+}
+
+void BlockedPopupContainerViewBridge::SetPosition() {
+ // Doesn't ever get called, also a no-op on GTK.
+ NOTIMPLEMENTED();
+}
+
+void BlockedPopupContainerViewBridge::ShowView() {
+ [controller_ show];
+}
+
+void BlockedPopupContainerViewBridge::UpdateLabel() {
+ [controller_ update];
+}
+
+void BlockedPopupContainerViewBridge::HideView() {
+ [controller_ hide];
+}
+
+void BlockedPopupContainerViewBridge::Destroy() {
+ [controller_ autorelease];
+}
diff --git a/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm b/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm
new file mode 100644
index 0000000..e2f5a7e
--- /dev/null
+++ b/chrome/browser/cocoa/blocked_popup_container_controller_unittest.mm
@@ -0,0 +1,85 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "app/app_paths.h"
+#include "base/path_service.h"
+#import "chrome/browser/cocoa/blocked_popup_container_controller.h"
+#include "chrome/browser/cocoa/browser_test_helper.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "chrome/browser/renderer_host/test_render_view_host.h"
+#include "net/base/net_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace {
+const std::string host1 = "host1";
+} // namespace
+
+class BlockedPopupContainerControllerTest : public RenderViewHostTestHarness {
+ public:
+ CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc...
+
+ virtual void SetUp() {
+ RenderViewHostTestHarness::SetUp();
+ container_ = BlockedPopupContainer::Create(contents(), profile());
+ cocoa_controller_ = [[BlockedPopupContainerController alloc]
+ initWithContainer:container_];
+ EXPECT_TRUE([cocoa_controller_ bridge]);
+ container_->set_view([cocoa_controller_ bridge]);
+ contents_->set_blocked_popup_container(container_);
+ }
+
+ virtual void TearDown() {
+ // This will also signal the Cocoa controller to delete itself with a
+ // Destroy() mesage to the bridge.
+ container_->Destroy();
+ contents_->set_blocked_popup_container(NULL);
+ }
+
+ TabContents* BuildTabContents() {
+ // This will be deleted when the TabContents goes away.
+ SiteInstance* instance = SiteInstance::CreateSiteInstance(profile_.get());
+
+ // Set up and use TestTabContents here.
+ return new TestTabContents(profile_.get(), instance);
+ }
+
+ GURL GetTestCase(const std::string& file) {
+ FilePath filename;
+ PathService::Get(app::DIR_TEST_DATA, &filename);
+ filename = filename.AppendASCII("constrained_files");
+ filename = filename.AppendASCII(file);
+ return net::FilePathToFileURL(filename);
+ }
+
+ BlockedPopupContainer* container_;
+ BlockedPopupContainerController* cocoa_controller_;
+};
+
+TEST_F(BlockedPopupContainerControllerTest, BasicPopupBlock) {
+ // This is taken from the popup blocker unit test.
+ TabContents* popup = BuildTabContents();
+ popup->controller().LoadURLLazily(GetTestCase("error"), GURL(),
+ PageTransition::LINK,
+ L"", NULL);
+ container_->AddTabContents(popup, gfx::Rect(), host1);
+ EXPECT_EQ(container_->GetBlockedPopupCount(), static_cast<size_t>(1));
+ EXPECT_EQ(container_->GetTabContentsAt(0), popup);
+ EXPECT_FALSE(container_->IsHostWhitelisted(0));
+
+ // Ensure the view has been displayed. If it has a superview, then ShowView()
+ // has been called on the bridge. If the label has a string, then
+ // UpdateLabel() has been called.
+ EXPECT_TRUE([cocoa_controller_ view]);
+ EXPECT_TRUE([[cocoa_controller_ view] superview]);
+ EXPECT_TRUE([[(NSTextField*)[cocoa_controller_ label]
+ stringValue] length] > 0);
+
+ // Close the popup and verify it's no longer in the view hierarchy. This
+ // means HideView() has been called.
+ [cocoa_controller_ closePopup:nil];
+ EXPECT_FALSE([[cocoa_controller_ view] superview]);
+}