summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/notifications/balloon_controller.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/cocoa/notifications/balloon_controller.mm')
-rw-r--r--chrome/browser/cocoa/notifications/balloon_controller.mm306
1 files changed, 306 insertions, 0 deletions
diff --git a/chrome/browser/cocoa/notifications/balloon_controller.mm b/chrome/browser/cocoa/notifications/balloon_controller.mm
new file mode 100644
index 0000000..f452cb4
--- /dev/null
+++ b/chrome/browser/cocoa/notifications/balloon_controller.mm
@@ -0,0 +1,306 @@
+// Copyright (c) 2010 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.
+
+#include "chrome/browser/cocoa/notifications/balloon_controller.h"
+
+#include "app/l10n_util.h"
+#import "base/cocoa_protocols_mac.h"
+#import "base/scoped_nsobject.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/cocoa/notifications/balloon_view_host_mac.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/profile.h"
+#include "grit/generated_resources.h"
+
+namespace {
+
+// Margin, in pixels, between the notification frame and the contents
+// of the notification.
+const int kTopMargin = 2;
+const int kBottomMargin = 2;
+const int kLeftMargin = 2;
+const int kRightMargin = 2;
+
+// How many pixels of overlap there is between the shelf top and the
+// balloon bottom.
+const int kShelfBorderTopOverlap = 6;
+
+// Properties of the dismiss button.
+const int kDismissButtonWidth = 52;
+const int kDismissButtonHeight = 18;
+
+// Properties of the options menu.
+const int kOptionsMenuWidth = 52;
+const int kOptionsMenuHeight = 18;
+
+// Properties of the origin label.
+const int kLeftLabelMargin = 4;
+const int kLabelHeight = 16;
+
+// TODO(johnnyg): http://crbug.com/34826 Add a shadow for the frame.
+const int kLeftShadowWidth = 0;
+const int kRightShadowWidth = 0;
+const int kTopShadowWidth = 0;
+const int kBottomShadowWidth = 0;
+
+// The shelf height for the system default font size. It is scaled
+// with changes in the default font size.
+const int kDefaultShelfHeight = 22;
+
+} // namespace
+
+@interface BalloonController (InternalLayout)
+// The following are all internal methods to calculate the dimensions of
+// subviews.
+- (NSPoint)contentsOffset;
+- (int)shelfHeight;
+- (int)balloonFrameHeight;
+- (NSRect)contentsRectangle;
+- (NSRect)closeButtonBounds;
+- (NSRect)optionsMenuBounds;
+- (NSRect)labelBounds;
+@end
+
+@implementation BalloonController
+
+- (id)initWithBalloon:(Balloon*)balloon {
+ NSString* sourceLabelText = l10n_util::GetNSStringF(
+ IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
+ WideToUTF16(balloon->notification().display_source()));
+ NSString* optionsText =
+ l10n_util::GetNSString(IDS_NOTIFICATION_OPTIONS_MENU_LABEL);
+ NSString* dismissText =
+ l10n_util::GetNSString(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL);
+ NSString* revokeText =
+ l10n_util::GetNSStringF(IDS_NOTIFICATION_BALLOON_REVOKE_MESSAGE,
+ WideToUTF16(balloon->notification().display_source()));
+
+ balloon_ = balloon;
+
+ frameContainer_.reset([[NSWindow alloc]
+ initWithContentRect:NSZeroRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:YES]);
+ [frameContainer_ setAlphaValue:1.0];
+ [frameContainer_ setOpaque:NO];
+ [frameContainer_ setLevel:NSFloatingWindowLevel];
+
+ if ((self = [self initWithWindow:frameContainer_.get()])) {
+ // Position of the balloon.
+ int x = balloon_->position().x();
+ int y = balloon_->position().y();
+ int w = [self desiredTotalWidth];
+ int h = [self desiredTotalHeight];
+
+ NSView* contentView = [frameContainer_ contentView];
+
+ frameView_.reset([[BalloonViewCocoa alloc]
+ initWithFrame:NSMakeRect(0,
+ [self shelfHeight],
+ w,
+ [self balloonFrameHeight])]);
+ [contentView addSubview:frameView_.get()];
+
+ htmlContainer_.reset(
+ [[NSView alloc] initWithFrame:[self contentsRectangle]]);
+ [htmlContainer_ setNeedsDisplay:YES];
+ [htmlContainer_ setFrame:[self contentsRectangle]];
+ [frameView_ addSubview:htmlContainer_.get()];
+
+ htmlContents_.reset(new BalloonViewHost(balloon));
+ [self initializeHost];
+
+ scoped_nsobject<NSView> shelfView([[BalloonShelfViewCocoa alloc]
+ initWithFrame:NSMakeRect(0,
+ 0,
+ w,
+ [self shelfHeight]+kShelfBorderTopOverlap)]);
+ [contentView addSubview:shelfView.get()
+ positioned:NSWindowBelow
+ relativeTo:htmlContainer_.get()];
+
+ optionsMenu_.reset([[NSMenu alloc] init]);
+ [optionsMenu_ addItemWithTitle:revokeText
+ action:@selector(permissionRevoked:)
+ keyEquivalent:@""];
+
+
+ // Creating UI elements by hand for easier parity with other platforms.
+ // TODO(johnnyg): http://crbug.com/34627
+ // Investigate converting this to a nib.
+ scoped_nsobject<BalloonButtonCell> closeButtonCell(
+ [[BalloonButtonCell alloc] initTextCell:dismissText]);
+ scoped_nsobject<NSButton> closeButton(
+ [[NSButton alloc] initWithFrame:[self closeButtonBounds]]);
+ [shelfView addSubview:closeButton.get()];
+ [closeButton setCell:closeButtonCell.get()];
+ [closeButton setTarget:self];
+ [closeButton setAction:@selector(closeButtonPressed:)];
+ [closeButtonCell setTextColor:[NSColor whiteColor]];
+
+ scoped_nsobject<BalloonButtonCell> optionsButtonCell(
+ [[BalloonButtonCell alloc] initTextCell:optionsText]);
+ scoped_nsobject<NSButton> optionsButton(
+ [[NSButton alloc] initWithFrame:[self optionsMenuBounds]]);
+ [shelfView addSubview:optionsButton.get()];
+ [optionsButton setCell:optionsButtonCell.get()];
+ [optionsButton setTarget:self];
+ [optionsButton setAction:@selector(optionsButtonPressed:)];
+ [optionsButtonCell setTextColor:[NSColor whiteColor]];
+
+ scoped_nsobject<NSTextField> originLabel([[NSTextField alloc] init]);
+ [shelfView addSubview:originLabel.get()];
+ [originLabel setEditable:NO];
+ [originLabel setBezeled:NO];
+ [originLabel setSelectable:NO];
+ [originLabel setDrawsBackground:NO];
+ [[originLabel cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+ [[originLabel cell] setTextColor:[NSColor whiteColor]];
+ [originLabel setStringValue:sourceLabelText];
+ [originLabel setFrame:[self labelBounds]];
+ [originLabel setFont:
+ [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+
+ [frameContainer_ setFrame:NSMakeRect(x, y, w, h) display:YES];
+ [frameContainer_ setDelegate:self];
+ }
+ return self;
+}
+
+- (IBAction)closeButtonPressed:(id)sender {
+ [self closeBalloon:YES];
+}
+
+- (IBAction)optionsButtonPressed:(id)sender {
+ [NSMenu popUpContextMenu:optionsMenu_
+ withEvent:[NSApp currentEvent]
+ forView:frameView_];
+}
+
+- (IBAction)permissionRevoked:(id)sender {
+ DesktopNotificationService* service =
+ balloon_->profile()->GetDesktopNotificationService();
+ service->DenyPermission(balloon_->notification().origin_url());
+}
+
+- (void)closeBalloon:(bool)byUser {
+ DCHECK(balloon_);
+ [self close];
+ htmlContents_->Shutdown();
+ balloon_->OnClose(byUser);
+ balloon_ = NULL;
+}
+
+- (void)repositionToBalloon {
+ DCHECK(balloon_);
+ int x = balloon_->position().x();
+ int y = balloon_->position().y();
+ int w = [self desiredTotalWidth];
+ int h = [self desiredTotalHeight];
+
+ NSRect frame = NSMakeRect(x, y, w, h);
+
+ htmlContents_->UpdateActualSize(balloon_->content_size());
+ [htmlContainer_ setFrame:[self contentsRectangle]];
+ [frameView_ setFrame:NSMakeRect(0,
+ [self shelfHeight],
+ w,
+ [self balloonFrameHeight])];
+
+ [animation_ stopAnimation];
+
+ NSDictionary* dict =
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ frameContainer_.get(), NSViewAnimationTargetKey,
+ [NSValue valueWithRect:frame], NSViewAnimationEndFrameKey, nil];
+
+ animation_.reset([[NSViewAnimation alloc]
+ initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]]);
+ [animation_ startAnimation];
+}
+
+// Returns the total width the view should be to accommodate the balloon.
+- (int)desiredTotalWidth {
+ return (balloon_ ? balloon_->content_size().width() : 0) +
+ kLeftMargin + kRightMargin + kLeftShadowWidth + kRightShadowWidth;
+}
+
+// Returns the total height the view should be to accommodate the balloon.
+- (int)desiredTotalHeight {
+ return (balloon_ ? balloon_->content_size().height() : 0) +
+ kTopMargin + kBottomMargin + kTopShadowWidth + kBottomShadowWidth +
+ [self shelfHeight];
+}
+
+// Relative to the lower left of the frame, above the shelf.
+- (NSPoint)contentsOffset {
+ return NSMakePoint(kLeftShadowWidth + kLeftMargin,
+ kBottomShadowWidth + kBottomMargin);
+}
+
+// Returns the height of the shelf in pixels.
+- (int)shelfHeight {
+ // TODO(johnnyg): add scaling here.
+ return kDefaultShelfHeight;
+}
+
+// Returns the height of the balloon contents frame in pixels.
+- (int)balloonFrameHeight {
+ return [self desiredTotalHeight] - [self shelfHeight];
+}
+
+// Relative to the lower-left of the frame.
+- (NSRect)contentsRectangle {
+ gfx::Size contentSize = balloon_->content_size();
+ NSPoint offset = [self contentsOffset];
+ return NSMakeRect(offset.x, offset.y,
+ contentSize.width(), contentSize.height());
+}
+
+// Returns the bounds of the close button.
+- (NSRect)closeButtonBounds {
+ return NSMakeRect(
+ [self desiredTotalWidth] - kDismissButtonWidth - kRightMargin,
+ kBottomMargin,
+ kDismissButtonWidth,
+ kDismissButtonHeight);
+}
+
+// Returns the bounds of the button which opens the options menu.
+- (NSRect)optionsMenuBounds {
+ return NSMakeRect(
+ [self desiredTotalWidth] -
+ kDismissButtonWidth - kOptionsMenuWidth - kRightMargin,
+ kBottomMargin,
+ kOptionsMenuWidth,
+ kOptionsMenuHeight);
+}
+
+// Returns the bounds of the label showing the origin of the notification.
+- (NSRect)labelBounds {
+ return NSMakeRect(
+ kLeftLabelMargin,
+ kBottomMargin,
+ [self desiredTotalWidth] -
+ kDismissButtonWidth - kOptionsMenuWidth - kRightMargin,
+ kLabelHeight);
+}
+
+// Initializes the renderer host showing the HTML contents.
+- (void)initializeHost {
+ htmlContents_->Init();
+ gfx::NativeView contents = htmlContents_->native_view();
+ [htmlContainer_ addSubview:contents];
+}
+
+// NSWindowDelegate notification.
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+}
+
+@end