diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-26 21:45:34 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-26 21:45:34 +0000 |
commit | 96788b0612875c0d12584757b63f02112e9541a7 (patch) | |
tree | d7eb82156c83b850d2714110dd7d8bb7aad60c41 | |
parent | 21ca7bf8f06e3b6e608f26eed8dce30515721b86 (diff) | |
download | chromium_src-96788b0612875c0d12584757b63f02112e9541a7.zip chromium_src-96788b0612875c0d12584757b63f02112e9541a7.tar.gz chromium_src-96788b0612875c0d12584757b63f02112e9541a7.tar.bz2 |
Mac: First run bubble.
Add a BaseBubbleController. Move ContentBlockedBubbleController to use it (other bubbles will follow in later CLs), add FIrstRunBubbleController which uses it.
Move some l10n stuff to l10n_util and use that, too.
Update first run code to actually call the bubble code. Fix a double free while I'm at it (the scoped_ptr<> in DoFirstRun() already does the freeing, no need to do it in FirstRunDone())
BUG=27489,36366
TEST=Firstrun bubble shows up when starting chrome with --first-run, doesn't if starting chrome without that flag. Content blocked bubbles still work.
Review URL: http://codereview.chromium.org/2822026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50940 0039d316-1c4b-4281-b951-d872f2087c98
25 files changed, 964 insertions, 185 deletions
diff --git a/chrome/app/nibs/FirstRunBubble.xib b/chrome/app/nibs/FirstRunBubble.xib new file mode 100644 index 0000000..f2667cc --- /dev/null +++ b/chrome/app/nibs/FirstRunBubble.xib @@ -0,0 +1,498 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03"> + <data> + <int key="IBDocument.SystemTarget">1050</int> + <string key="IBDocument.SystemVersion">9L31a</string> + <string key="IBDocument.InterfaceBuilderVersion">680</string> + <string key="IBDocument.AppKitVersion">949.54</string> + <string key="IBDocument.HIToolboxVersion">353.00</string> + <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="4"/> + </object> + <object class="NSArray" key="IBDocument.PluginDependencies"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSCustomObject" id="1001"> + <string key="NSClassName">FirstRunBubbleController</string> + </object> + <object class="NSCustomObject" id="1003"> + <string key="NSClassName">FirstResponder</string> + </object> + <object class="NSCustomObject" id="1004"> + <string key="NSClassName">NSApplication</string> + </object> + <object class="NSWindowTemplate" id="1005"> + <int key="NSWindowStyleMask">15</int> + <int key="NSWindowBacking">2</int> + <string key="NSWindowRect">{{196, 426}, {428, 84}}</string> + <int key="NSWTFlags">536873984</int> + <string key="NSWindowTitle">Window</string> + <string key="NSWindowClass">InfoBubbleWindow</string> + <nil key="NSViewClass"/> + <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <object class="NSView" key="NSWindowView" id="1006"> + <reference key="NSNextResponder"/> + <int key="NSvFlags">256</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSCustomView" id="301729179"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">274</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSTextField" id="664006571"> + <reference key="NSNextResponder" ref="301729179"/> + <int key="NSvFlags">266</int> + <string key="NSFrame">{{17, 17}, {367, 17}}</string> + <reference key="NSSuperview" ref="301729179"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="114775885"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string key="NSContents">^IDS_FR_BUBBLE_SUBTEXT</string> + <object class="NSFont" key="NSSupport"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">1.300000e+01</double> + <int key="NSfFlags">1044</int> + </object> + <reference key="NSControlView" ref="664006571"/> + <object class="NSColor" key="NSBackgroundColor" id="8127014"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor" id="573452522"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlTextColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + </object> + </object> + </object> + </object> + <object class="NSTextField" id="944552054"> + <reference key="NSNextResponder" ref="301729179"/> + <int key="NSvFlags">266</int> + <string key="NSFrame">{{17, 42}, {394, 22}}</string> + <reference key="NSSuperview" ref="301729179"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="175463096"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">1346371584</int> + <string key="NSContents">^IDS_FR_SE_BUBBLE_TITLE</string> + <object class="NSFont" key="NSSupport"> + <string key="NSName">LucidaGrande-Bold</string> + <double key="NSSize">1.800000e+01</double> + <int key="NSfFlags">16</int> + </object> + <reference key="NSControlView" ref="944552054"/> + <reference key="NSBackgroundColor" ref="8127014"/> + <reference key="NSTextColor" ref="573452522"/> + </object> + </object> + </object> + <string key="NSFrameSize">{428, 84}</string> + <reference key="NSSuperview" ref="1006"/> + <string key="NSClassName">InfoBubbleView</string> + </object> + </object> + <string key="NSFrameSize">{428, 84}</string> + <reference key="NSSuperview"/> + </object> + <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string> + <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> + </object> + <object class="NSCustomObject" id="670916757"> + <string key="NSClassName">ChromeUILocalizer</string> + </object> + <object class="NSCustomObject" id="684547419"> + <string key="NSClassName">GTMUILocalizerAndLayoutTweaker</string> + </object> + </object> + <object class="IBObjectContainer" key="IBDocument.Objects"> + <object class="NSMutableArray" key="connectionRecords"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">window</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="1005"/> + </object> + <int key="connectionID">3</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">bubble_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="301729179"/> + </object> + <int key="connectionID">5</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="1005"/> + <reference key="destination" ref="1001"/> + </object> + <int key="connectionID">6</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">localizer_</string> + <reference key="source" ref="684547419"/> + <reference key="destination" ref="670916757"/> + </object> + <int key="connectionID">22</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">uiObject_</string> + <reference key="source" ref="684547419"/> + <reference key="destination" ref="1005"/> + </object> + <int key="connectionID">23</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">header_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="944552054"/> + </object> + <int key="connectionID">51</int> + </object> + </object> + <object class="IBMutableOrderedSet" key="objectRecords"> + <object class="NSArray" key="orderedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBObjectRecord"> + <int key="objectID">0</int> + <object class="NSArray" key="object" id="1002"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <reference key="children" ref="1000"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="1001"/> + <reference key="parent" ref="1002"/> + <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="1003"/> + <reference key="parent" ref="1002"/> + <string key="objectName">First Responder</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-3</int> + <reference key="object" ref="1004"/> + <reference key="parent" ref="1002"/> + <string key="objectName">Application</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">1</int> + <reference key="object" ref="1005"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="1006"/> + </object> + <reference key="parent" ref="1002"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">2</int> + <reference key="object" ref="1006"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="301729179"/> + </object> + <reference key="parent" ref="1005"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">4</int> + <reference key="object" ref="301729179"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="664006571"/> + <reference ref="944552054"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">20</int> + <reference key="object" ref="670916757"/> + <reference key="parent" ref="1002"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">21</int> + <reference key="object" ref="684547419"/> + <reference key="parent" ref="1002"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">47</int> + <reference key="object" ref="664006571"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="114775885"/> + </object> + <reference key="parent" ref="301729179"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">48</int> + <reference key="object" ref="114775885"/> + <reference key="parent" ref="664006571"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">49</int> + <reference key="object" ref="944552054"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="175463096"/> + </object> + <reference key="parent" ref="301729179"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">50</int> + <reference key="object" ref="175463096"/> + <reference key="parent" ref="944552054"/> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="flattenedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMutableArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>-1.IBPluginDependency</string> + <string>-2.IBPluginDependency</string> + <string>-3.IBPluginDependency</string> + <string>1.IBEditorWindowLastContentRect</string> + <string>1.IBPluginDependency</string> + <string>1.IBWindowTemplateEditedContentRect</string> + <string>1.NSWindowTemplate.visibleAtLaunch</string> + <string>1.WindowOrigin</string> + <string>1.editorWindowContentRectSynchronizationRect</string> + <string>2.IBPluginDependency</string> + <string>20.IBPluginDependency</string> + <string>21.IBPluginDependency</string> + <string>4.IBPluginDependency</string> + <string>47.IBPluginDependency</string> + <string>48.IBPluginDependency</string> + <string>49.IBPluginDependency</string> + <string>50.IBPluginDependency</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{227, 905}, {428, 84}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{227, 905}, {428, 84}}</string> + <boolean value="NO"/> + <string>{196, 240}</string> + <string>{{357, 418}, {480, 270}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + </object> + <object class="NSMutableDictionary" key="unlocalizedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="activeLocalization"/> + <object class="NSMutableDictionary" key="localizations"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="sourceID"/> + <int key="maxID">51</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <object class="NSMutableArray" key="referencedPartialClassDescriptions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">BaseBubbleController</string> + <string key="superclassName">NSWindowController</string> + <object class="NSMutableDictionary" key="outlets"> + <string key="NS.key.0">bubble_</string> + <string key="NS.object.0">InfoBubbleView</string> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/base_bubble_controller.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">ChromeEventProcessingWindow</string> + <string key="superclassName">NSWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/chrome_event_processing_window.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">ChromeUILocalizer</string> + <string key="superclassName">GTMUILocalizer</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/ui_localizer.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">FirstRunBubbleController</string> + <string key="superclassName">BaseBubbleController</string> + <object class="NSMutableDictionary" key="outlets"> + <string key="NS.key.0">header_</string> + <string key="NS.object.0">NSTextField</string> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/first_run_bubble_controller.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">GTMUILocalizer</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMutableArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>otherObjectToLocalize_</string> + <string>owner_</string> + <string>yetAnotherObjectToLocalize_</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>id</string> + <string>id</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">../third_party/GTM/AppKit/GTMUILocalizer.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">GTMUILocalizerAndLayoutTweaker</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMutableArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>localizerOwner_</string> + <string>localizer_</string> + <string>uiObject_</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>GTMUILocalizer</string> + <string>id</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">../third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">InfoBubbleView</string> + <string key="superclassName">NSView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/info_bubble_view.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">InfoBubbleWindow</string> + <string key="superclassName">ChromeEventProcessingWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/info_bubble_window.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">../third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/objc_zombie.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/status_bubble_mac.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/tab_strip_model_observer_bridge.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/chrome_browser_window.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/themed_window.h</string> + </object> + </object> + </object> + </object> + <int key="IBDocument.localizationMode">0</int> + <string key="IBDocument.LastKnownRelativeProjectPath">../../chrome.xcodeproj</string> + <int key="IBDocument.defaultPropertyAccessControl">3</int> + </data> +</archive> diff --git a/chrome/browser/cocoa/base_bubble_controller.h b/chrome/browser/cocoa/base_bubble_controller.h new file mode 100644 index 0000000..795f1a1 --- /dev/null +++ b/chrome/browser/cocoa/base_bubble_controller.h @@ -0,0 +1,53 @@ +// 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. + +#import <Cocoa/Cocoa.h> + +#import "base/cocoa_protocols_mac.h" +#include "base/scoped_nsobject.h" +#include "base/scoped_ptr.h" + +@class InfoBubbleView; + +// Base class for bubble controllers. Manages a xib that contains an +// InfoBubbleWindow which contains an InfoBubbleView. Contains code to close +// the bubble window on clicks outside of the window, and the like. +// To use this class: +// 1. Create a new xib that contains a window. Change the window's class to +// InfoBubbleWindow. Give it a child view that autosizes to the window's full +// size, give it class InfoBubbleView. Make the controller the window's +// delegate. +// 2. Create a subclass of BaseBubbleController. +// 3. Change the xib's File Owner to your subclass. +// 4. Hook up the File Owner's |bubble_| to the InfoBubbleView in the xib. +@interface BaseBubbleController : NSWindowController<NSWindowDelegate> { + @private + NSWindow* parentWindow_; // weak + NSPoint anchor_; + IBOutlet InfoBubbleView* bubble_; // to set arrow position +} + +// Creates a bubble. |nibPath| is just the basename, e.g. @"FirstRunBubble". +// |anchoredAt| is in screen space. You need to call -showWindow: to make the +// bubble visible. It will autorelease itself when the user dismisses the +// bubble. +// This is the designated initializer. +- (id)initWithWindowNibPath:(NSString*)nibPath + parentWindow:(NSWindow*)parentWindow + anchoredAt:(NSPoint)anchoredAt; + + +// Creates a bubble. |nibPath| is just the basename, e.g. @"FirstRunBubble". +// |view| must be in a window. The bubble will point at |offset| relative to +// |view|'s lower left corner. You need to call -showWindow: to make the +// bubble visible. It will autorelease itself when the user dismisses the +// bubble. +- (id)initWithWindowNibPath:(NSString*)nibPath + relativeToView:(NSView*)view + offset:(NSPoint)offset; + + +@property (nonatomic, readonly) InfoBubbleView* bubble; + +@end diff --git a/chrome/browser/cocoa/base_bubble_controller.mm b/chrome/browser/cocoa/base_bubble_controller.mm new file mode 100644 index 0000000..b155a4f --- /dev/null +++ b/chrome/browser/cocoa/base_bubble_controller.mm @@ -0,0 +1,123 @@ +// 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. + +#import "chrome/browser/cocoa/base_bubble_controller.h" + +#include "app/l10n_util.h" +#include "base/logging.h" +#include "base/mac_util.h" +#include "base/string_util.h" +#import "chrome/browser/cocoa/info_bubble_view.h" +#include "grit/generated_resources.h" + +@implementation BaseBubbleController + +@synthesize bubble = bubble_; + +- (id)initWithWindowNibPath:(NSString*)nibPath + parentWindow:(NSWindow*)parentWindow + anchoredAt:(NSPoint)anchoredAt { + nibPath = [mac_util::MainAppBundle() pathForResource:nibPath + ofType:@"nib"]; + if ((self = [super initWithWindowNibPath:nibPath owner:self])) { + parentWindow_ = parentWindow; + anchor_ = anchoredAt; + + // Watch to see if the parent window closes, and if so, close this one. + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(parentWindowWillClose:) + name:NSWindowWillCloseNotification + object:parentWindow_]; + } + return self; +} + +- (id)initWithWindowNibPath:(NSString*)nibPath + relativeToView:(NSView*)view + offset:(NSPoint)offset { + DCHECK([view window]); + NSWindow* window = [view window]; + NSRect bounds = [view convertRect:[view bounds] toView:nil]; + NSPoint anchor = NSMakePoint(NSMinX(bounds) + offset.x, + NSMinY(bounds) + offset.y); + anchor = [window convertBaseToScreen:anchor]; + return [self initWithWindowNibPath:nibPath + parentWindow:window + anchoredAt:anchor]; +} + + +- (void)awakeFromNib { + // Check all connections have been made in Interface Builder. + DCHECK([self window]); + DCHECK(bubble_); + DCHECK_EQ(self, [[self window] delegate]); + + [bubble_ setBubbleType:info_bubble::kWhiteInfoBubble]; + [bubble_ setArrowLocation:info_bubble::kTopRight]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)parentWindowWillClose:(NSNotification*)notification { + [self close]; +} + +- (void)windowWillClose:(NSNotification*)notification { + // We caught a close so we don't need to watch for the parent closing. + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self autorelease]; +} + +// We want this to be a child of a browser window. addChildWindow: +// (called from this function) will bring the window on-screen; +// unfortunately, [NSWindowController showWindow:] will also bring it +// on-screen (but will cause unexpected changes to the window's +// position). We cannot have an addChildWindow: and a subsequent +// showWindow:. Thus, we have our own version. +- (void)showWindow:(id)sender { + NSWindow* window = [self window]; // completes nib load + + NSPoint origin = anchor_; + NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset + + info_bubble::kBubbleArrowWidth / 2.0, 0); + offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil]; + origin.x += offsets.width; + if ([bubble_ arrowLocation] == info_bubble::kTopRight) + origin.x -= NSWidth([window frame]); + origin.y -= NSHeight([window frame]); + [window setFrameOrigin:origin]; + [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; + [window makeKeyAndOrderFront:self]; +} + +- (void)close { + [parentWindow_ removeChildWindow:[self window]]; + [super close]; +} + +// The controller is the delegate of the window so it receives did resign key +// notifications. When key is resigned mirror Windows behavior and close the +// window. +- (void)windowDidResignKey:(NSNotification*)notification { + NSWindow* window = [self window]; + DCHECK_EQ([notification object], window); + if ([window isVisible]) { + // If the window isn't visible, it is already closed, and this notification + // has been sent as part of the closing operation, so no need to close. + [self close]; + } +} + +// By implementing this, ESC causes the window to go away. +- (IBAction)cancel:(id)sender { + // This is not a "real" cancel as potential changes to the radio group are not + // undone. That's ok. + [self close]; +} +@end // BaseBubbleController diff --git a/chrome/browser/cocoa/content_blocked_bubble_controller.h b/chrome/browser/cocoa/content_blocked_bubble_controller.h index 669c437..6bb7c90 100644 --- a/chrome/browser/cocoa/content_blocked_bubble_controller.h +++ b/chrome/browser/cocoa/content_blocked_bubble_controller.h @@ -10,6 +10,7 @@ #import "base/cocoa_protocols_mac.h" #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" +#import "chrome/browser/cocoa/base_bubble_controller.h" class ContentSettingBubbleModel; @class InfoBubbleView; @@ -21,13 +22,8 @@ typedef std::map<NSButton*, int> PopupLinks; } // Manages a "content blocked" bubble. -@interface ContentBlockedBubbleController - : NSWindowController<NSWindowDelegate> { +@interface ContentBlockedBubbleController : BaseBubbleController { @private - NSWindow* parentWindow_; // weak - NSPoint anchor_; - IBOutlet InfoBubbleView* bubble_; // to set arrow position - IBOutlet NSTextField* titleLabel_; IBOutlet NSMatrix* allowBlockRadioGroup_; diff --git a/chrome/browser/cocoa/content_blocked_bubble_controller.mm b/chrome/browser/cocoa/content_blocked_bubble_controller.mm index e18370f..a30b336 100644 --- a/chrome/browser/cocoa/content_blocked_bubble_controller.mm +++ b/chrome/browser/cocoa/content_blocked_bubble_controller.mm @@ -6,17 +6,14 @@ #include "app/l10n_util.h" #include "base/logging.h" -#include "base/mac_util.h" -#include "base/string_util.h" #include "base/sys_string_conversions.h" #include "chrome/browser/blocked_popup_container.h" #import "chrome/browser/cocoa/content_settings_dialog_controller.h" #import "chrome/browser/cocoa/hyperlink_button_cell.h" #import "chrome/browser/cocoa/info_bubble_view.h" +#import "chrome/browser/cocoa/l10n_util.h" #include "chrome/browser/content_setting_bubble_model.h" #include "chrome/browser/host_content_settings_map.h" -#include "chrome/common/notification_service.h" -#include "chrome/common/notification_type.h" #include "grit/generated_resources.h" #include "skia/ext/skia_utils_mac.h" #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" @@ -56,17 +53,6 @@ const int kGeoHostPadding = 4; // Minimal padding between "Manage" and "Done" buttons. const int kManageDonePadding = 8; -// Like |ReplaceStringPlaceholders(const string16&, const string16&, size_t*)|, -// but for a NSString formatString. -NSString* ReplaceNSStringPlaceholders(NSString* formatString, - const string16& a, - size_t* offset) { - return base::SysUTF16ToNSString( - ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString), - a, - offset)); -} - void SetControlSize(NSControl* control, NSControlSize controlSize) { CGFloat fontSize = [NSFont systemFontSizeForControlSize:controlSize]; NSCell* cell = [control cell]; @@ -136,20 +122,11 @@ NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { nibPaths_requires_an_entry_for_every_setting_type); const int settingsType = model->content_type(); DCHECK_LT(settingsType, CONTENT_SETTINGS_NUM_TYPES); - NSString* nibPath = - [mac_util::MainAppBundle() pathForResource:nibPaths[settingsType] - ofType:@"nib"]; - if ((self = [super initWithWindowNibPath:nibPath owner:self])) { - parentWindow_ = parentWindow; - anchor_ = anchoredAt; + if ((self = [super initWithWindowNibPath:nibPaths[settingsType] + parentWindow:parentWindow + anchoredAt:anchoredAt])) { contentSettingBubbleModel_.reset(model.release()); - - // Watch to see if the parent window closes, and if so, close this one. - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - [center addObserver:self - selector:@selector(parentWindowWillClose:) - name:NSWindowWillCloseNotification - object:parentWindow_]; + [self showWindow:nil]; } return self; } @@ -184,7 +161,7 @@ NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { // Copy |host_| into radio group label. NSCell* radioCell = [allowBlockRadioGroup_ cellWithTag:kAllowTag]; - [radioCell setTitle:ReplaceNSStringPlaceholders( + [radioCell setTitle:cocoa_l10n_util::ReplaceNSStringPlaceholders( [radioCell title], UTF8ToUTF16(radioGroup.url.host()), NULL)]; // Layout radio group labels post-localization. @@ -218,7 +195,7 @@ NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { // If the link text is too long, clamp it. [button sizeToFit]; - int maxWidth = NSWidth([bubble_ frame]) - 2 * NSMinX(referenceFrame); + int maxWidth = NSWidth([[self bubble] frame]) - 2 * NSMinX(referenceFrame); NSRect buttonFrame = [button frame]; if (NSWidth(buttonFrame) > maxWidth) { buttonFrame.size.width = maxWidth; @@ -276,7 +253,7 @@ NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { title:base::SysUTF8ToNSString(title) icon:image referenceFrame:radioFrame]; - [bubble_ addSubview:button]; + [[self bubble] addSubview:button]; popupLinks_[button] = row; } } @@ -379,11 +356,8 @@ NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { } - (void)awakeFromNib { - DCHECK([self window]); - DCHECK_EQ(self, [[self window] delegate]); - - [bubble_ setBubbleType:info_bubble::kWhiteInfoBubble]; - [bubble_ setArrowLocation:info_bubble::kTopRight]; + [[self bubble] setBubbleType:info_bubble::kWhiteInfoBubble]; + [[self bubble] setArrowLocation:info_bubble::kTopRight]; // Adapt window size to bottom buttons. Do this before all other layouting. [self sizeToFitManageDoneButtons]; @@ -400,73 +374,6 @@ NSTextField* LabelWithFrame(NSString* text, const NSRect& frame) { } /////////////////////////////////////////////////////////////////////////////// -// Bubble-management related stuff - -// TODO(thakis): All that junk below should be in some superclass that all the -// bubble controllers (bookmark bubble, extension installed bubble, page/browser -// action bubble, content blocked bubble) derive from -- http://crbug.com/36366 - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [super dealloc]; -} - -- (void)parentWindowWillClose:(NSNotification*)notification { - [self close]; -} - -- (void)windowWillClose:(NSNotification*)notification { - // We caught a close so we don't need to watch for the parent closing. - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self autorelease]; -} - -// We want this to be a child of a browser window. addChildWindow: -// (called from this function) will bring the window on-screen; -// unfortunately, [NSWindowController showWindow:] will also bring it -// on-screen (but will cause unexpected changes to the window's -// position). We cannot have an addChildWindow: and a subsequent -// showWindow:. Thus, we have our own version. -- (void)showWindow:(id)sender { - NSWindow* window = [self window]; // completes nib load - - NSPoint origin = anchor_; - NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset + - info_bubble::kBubbleArrowWidth / 2.0, 0); - offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil]; - origin.x -= NSWidth([window frame]) - offsets.width; - origin.y -= NSHeight([window frame]); - [window setFrameOrigin:origin]; - [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; - [window makeKeyAndOrderFront:self]; -} - -- (void)close { - [parentWindow_ removeChildWindow:[self window]]; - [super close]; -} - -// The controller is the delegate of the window so it receives did resign key -// notifications. When key is resigned mirror Windows behavior and close the -// window. -- (void)windowDidResignKey:(NSNotification*)notification { - NSWindow* window = [self window]; - DCHECK_EQ([notification object], window); - if ([window isVisible]) { - // If the window isn't visible, it is already closed, and this notification - // has been sent as part of the closing operation, so no need to close. - [self close]; - } -} - -// By implementing this, ESC causes the window to go away. -- (IBAction)cancel:(id)sender { - // This is not a "real" cancel as potential changes to the radio group are not - // undone. That's ok. - [self close]; -} - -/////////////////////////////////////////////////////////////////////////////// // Actual application logic - (IBAction)allowBlockToggled:(id)sender { diff --git a/chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm b/chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm index a7b940e..31b56cf 100644 --- a/chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm +++ b/chrome/browser/cocoa/content_blocked_bubble_controller_unittest.mm @@ -49,7 +49,7 @@ TEST_F(ContentBlockedBubbleControllerTest, Init) { parentWindow:parent anchoredAt:NSMakePoint(50, 20)]; EXPECT_TRUE(controller != nil); - [controller showWindow:nil]; + EXPECT_TRUE([[controller window] isVisible]); [parent.get() close]; } } diff --git a/chrome/browser/cocoa/content_settings_dialog_controller.mm b/chrome/browser/cocoa/content_settings_dialog_controller.mm index d909b05..c635a95 100644 --- a/chrome/browser/cocoa/content_settings_dialog_controller.mm +++ b/chrome/browser/cocoa/content_settings_dialog_controller.mm @@ -28,32 +28,6 @@ namespace { // Stores the currently visible content settings dialog, if any. ContentSettingsDialogController* g_instance = nil; -// Walks views in top-down order, wraps each to their current width, and moves -// the latter ones down to prevent overlaps. -CGFloat VerticallyReflowGroup(NSArray* views) { - views = [views sortedArrayUsingFunction:cocoa_l10n_util::CompareFrameY - context:NULL]; - CGFloat localVerticalShift = 0; - for (NSInteger index = [views count] - 1; index >= 0; --index) { - NSView* view = [views objectAtIndex:index]; - - // Since the tab pane is in a horizontal resizer in IB, it's convenient - // to give all the subviews flexible width so that their sizes are - // autoupdated in IB. However, in chrome, the subviews shouldn't have - // flexible widths as this looks weird. - [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; - - NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view); - localVerticalShift += delta.height; - if (localVerticalShift) { - NSPoint origin = [view frame].origin; - origin.y -= localVerticalShift; - [view setFrameOrigin:origin]; - } - } - return localVerticalShift; -} - } // namespace @@ -196,8 +170,17 @@ class PrefObserverDisabler { // Adapt views to potentially long localized strings. CGFloat windowDelta = 0; for (NSTabViewItem* tab in [tabView_ tabViewItems]) { + NSArray* subviews = [[tab view] subviews]; windowDelta = MAX(windowDelta, - VerticallyReflowGroup([[tab view] subviews])); + cocoa_l10n_util::VerticallyReflowGroup(subviews)); + + for (NSView* view in subviews) { + // Since the tab pane is in a horizontal resizer in IB, it's convenient + // to give all the subviews flexible width so that their sizes are + // autoupdated in IB. However, in chrome, the subviews shouldn't have + // flexible widths as this looks weird. + [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + } } NSRect frame = [[self window] frame]; diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.mm b/chrome/browser/cocoa/extension_installed_bubble_controller.mm index b255d0e..69046ec 100644 --- a/chrome/browser/cocoa/extension_installed_bubble_controller.mm +++ b/chrome/browser/cocoa/extension_installed_bubble_controller.mm @@ -225,7 +225,7 @@ class ExtensionLoadedNotificationObserver : public NotificationObserver { NSPoint origin = [parentWindow_ convertBaseToScreen:[self calculateArrowPoint]]; NSSize offsets = NSMakeSize(info_bubble::kBubbleArrowXOffset + - info_bubble::kBubbleArrowWidth / 2.0, 0); + info_bubble::kBubbleArrowWidth / 2.0, 0); offsets = [[window contentView] convertSize:offsets toView:nil]; origin.x -= NSWidth([window frame]) - offsets.width; origin.y -= NSHeight([window frame]); diff --git a/chrome/browser/cocoa/first_run_bubble_controller.h b/chrome/browser/cocoa/first_run_bubble_controller.h new file mode 100644 index 0000000..4e5fac5 --- /dev/null +++ b/chrome/browser/cocoa/first_run_bubble_controller.h @@ -0,0 +1,24 @@ +// 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. + +#import <Cocoa/Cocoa.h> + +#import "chrome/browser/cocoa/base_bubble_controller.h" + +class Profile; + +// Manages the first run bubble. +@interface FirstRunBubbleController : BaseBubbleController { + @private + // Header label. + IBOutlet NSTextField* header_; + + Profile* profile_; +} + +// Creates and shows a firstRun bubble. ++ (FirstRunBubbleController*) showForView:(NSView*)view + offset:(NSPoint)offset + profile:(Profile*)profile; +@end diff --git a/chrome/browser/cocoa/first_run_bubble_controller.mm b/chrome/browser/cocoa/first_run_bubble_controller.mm new file mode 100644 index 0000000..6c4ea32 --- /dev/null +++ b/chrome/browser/cocoa/first_run_bubble_controller.mm @@ -0,0 +1,62 @@ +// 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. + +#import "chrome/browser/cocoa/first_run_bubble_controller.h" + +#include "app/l10n_util.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#import "chrome/browser/cocoa/l10n_util.h" +#import "chrome/browser/cocoa/info_bubble_view.h" +#include "chrome/browser/search_engines/util.h" +#include "grit/generated_resources.h" + +@interface FirstRunBubbleController(Private) +- (id)initRelativeToView:(NSView*)view + offset:(NSPoint)offset + profile:(Profile*)profile; +@end + +@implementation FirstRunBubbleController + ++ (FirstRunBubbleController*) showForView:(NSView*)view + offset:(NSPoint)offset + profile:(Profile*)profile { + // Autoreleases itself on bubble close. + return [[FirstRunBubbleController alloc] initRelativeToView:view + offset:offset + profile:profile]; +} + +- (id)initRelativeToView:(NSView*)view + offset:(NSPoint)offset + profile:(Profile*)profile { + if ((self = [super initWithWindowNibPath:@"FirstRunBubble" + relativeToView:view + offset:offset])) { + profile_ = profile; + [self showWindow:nil]; + } + return self; +} + +- (void)awakeFromNib { + [[self bubble] setBubbleType:info_bubble::kWhiteInfoBubble]; + + DCHECK(header_); + [header_ setStringValue:cocoa_l10n_util::ReplaceNSStringPlaceholders( + [header_ stringValue], GetDefaultSearchEngineName(profile_), NULL)]; + + // Adapt window size to bottom buttons. Do this before all other layouting. + CGFloat dy = cocoa_l10n_util::VerticallyReflowGroup([[self bubble] subviews]); + NSSize ds = NSMakeSize(0, dy); + ds = [[self bubble] convertSize:ds toView:nil]; + + NSRect frame = [[self window] frame]; + frame.origin.y -= ds.height; + frame.size.height += ds.height; + [[self window] setFrame:frame display:YES]; +} + +@end // FirstRunBubbleController diff --git a/chrome/browser/cocoa/first_run_bubble_controller_unittest.mm b/chrome/browser/cocoa/first_run_bubble_controller_unittest.mm new file mode 100644 index 0000000..a6009a6 --- /dev/null +++ b/chrome/browser/cocoa/first_run_bubble_controller_unittest.mm @@ -0,0 +1,43 @@ +// 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. + +#import "chrome/browser/cocoa/first_run_bubble_controller.h" + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#include "chrome/browser/cocoa/browser_test_helper.h" +#import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class FirstRunBubbleControllerTest : public CocoaTest { + public: + BrowserTestHelper helper_; +}; + +// Check that the bubble doesn't crash or leak. +TEST_F(FirstRunBubbleControllerTest, Init) { + scoped_nsobject<NSWindow> parent([[NSWindow alloc] + initWithContentRect:NSMakeRect(0, 0, 800, 600) + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]); + [parent setReleasedWhenClosed:NO]; + if (DebugUtil::BeingDebugged()) + [parent.get() orderFront:nil]; + else + [parent.get() orderBack:nil]; + + FirstRunBubbleController* controller = [FirstRunBubbleController + showForView:[parent.get() contentView] + offset:NSMakePoint(300, 300) + profile:helper_.profile()]; + EXPECT_TRUE(controller != nil); + EXPECT_TRUE([[controller window] isVisible]); + [parent.get() close]; +} + +} // namespace diff --git a/chrome/browser/cocoa/l10n_util.h b/chrome/browser/cocoa/l10n_util.h index 5e417a1..bb26327 100644 --- a/chrome/browser/cocoa/l10n_util.h +++ b/chrome/browser/cocoa/l10n_util.h @@ -4,6 +4,8 @@ #import <Cocoa/Cocoa.h> +#include "base/string16.h" + namespace cocoa_l10n_util { // Compare function for -[NSArray sortedArrayUsingFunction:context:] that @@ -16,4 +18,15 @@ NSInteger CompareFrameY(id view1, id view2, void* context); // anything else: do +[GTMUILocalizerAndLayoutTweaker sizeToFitView:] NSSize WrapOrSizeToFit(NSView* view); +// Walks views in top-down order, wraps each to their current width, and moves +// the latter ones down to prevent overlaps. Returns the vertical delta in view +// coordinates. +CGFloat VerticallyReflowGroup(NSArray* views); + +// Like |ReplaceStringPlaceholders(const string16&, const string16&, size_t*)|, +// but for a NSString formatString. +NSString* ReplaceNSStringPlaceholders(NSString* formatString, + const string16& a, + size_t* offset); + } // namespace cocoa_l10n_util diff --git a/chrome/browser/cocoa/l10n_util.mm b/chrome/browser/cocoa/l10n_util.mm index 91691ed..e39bdb3 100644 --- a/chrome/browser/cocoa/l10n_util.mm +++ b/chrome/browser/cocoa/l10n_util.mm @@ -4,6 +4,8 @@ #import "chrome/browser/cocoa/l10n_util.h" +#include "base/string_util.h" +#include "base/sys_string_conversions.h" #import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h" namespace cocoa_l10n_util { @@ -46,4 +48,31 @@ NSSize WrapOrSizeToFit(NSView* view) { return [GTMUILocalizerAndLayoutTweaker sizeToFitView:view]; } +CGFloat VerticallyReflowGroup(NSArray* views) { + views = [views sortedArrayUsingFunction:CompareFrameY + context:NULL]; + CGFloat localVerticalShift = 0; + for (NSInteger index = [views count] - 1; index >= 0; --index) { + NSView* view = [views objectAtIndex:index]; + + NSSize delta = WrapOrSizeToFit(view); + localVerticalShift += delta.height; + if (localVerticalShift) { + NSPoint origin = [view frame].origin; + origin.y -= localVerticalShift; + [view setFrameOrigin:origin]; + } + } + return localVerticalShift; +} + +NSString* ReplaceNSStringPlaceholders(NSString* formatString, + const string16& a, + size_t* offset) { + return base::SysUTF16ToNSString( + ReplaceStringPlaceholders(base::SysNSStringToUTF16(formatString), + a, + offset)); +} + } // namespace cocoa_l10n_util diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h index f7d77fe..6536a95 100644 --- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.h +++ b/chrome/browser/cocoa/location_bar/location_bar_view_mac.h @@ -47,9 +47,7 @@ class LocationBarViewMac : public AutocompleteEditController, virtual ~LocationBarViewMac(); // Overridden from LocationBar: - virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type) { - NOTIMPLEMENTED(); - } + virtual void ShowFirstRunBubble(FirstRun::BubbleType bubble_type); virtual std::wstring GetInputString() const; virtual WindowOpenDisposition GetWindowOpenDisposition() const; virtual PageTransition::Type GetPageTransition() const; @@ -433,6 +431,8 @@ class LocationBarViewMac : public AutocompleteEditController, // tab contents state. void RefreshContentSettingsViews(); + void ShowFirstRunBubbleInternal(FirstRun::BubbleType bubble_type); + scoped_ptr<AutocompleteEditViewMac> edit_view_; CommandUpdater* command_updater_; // Weak, owned by Browser. @@ -477,6 +477,9 @@ class LocationBarViewMac : public AutocompleteEditController, // Used to register for notifications received by NotificationObserver. NotificationRegistrar registrar_; + // Used to schedule a task for the first run info bubble. + ScopedRunnableMethodFactory<LocationBarViewMac> first_run_bubble_; + DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac); }; diff --git a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm index af31131..146128d 100644 --- a/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm +++ b/chrome/browser/cocoa/location_bar/location_bar_view_mac.mm @@ -20,6 +20,7 @@ #include "chrome/browser/cocoa/event_utils.h" #import "chrome/browser/cocoa/extensions/extension_action_context_menu.h" #import "chrome/browser/cocoa/extensions/extension_popup_controller.h" +#import "chrome/browser/cocoa/first_run_bubble_controller.h" #import "chrome/browser/cocoa/location_bar/autocomplete_text_field.h" #import "chrome/browser/cocoa/location_bar/autocomplete_text_field_cell.h" #include "chrome/browser/command_updater.h" @@ -79,7 +80,8 @@ LocationBarViewMac::LocationBarViewMac( profile_(profile), browser_(browser), toolbar_model_(toolbar_model), - transition_(PageTransition::TYPED) { + transition_(PageTransition::TYPED), + first_run_bubble_(this) { for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { ContentSettingImageView* content_setting_view = new ContentSettingImageView(static_cast<ContentSettingsType>(i), this, @@ -109,6 +111,25 @@ LocationBarViewMac::~LocationBarViewMac() { [cell setStarIconView:NULL]; } +void LocationBarViewMac::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) { + // We need the browser window to be shown before we can show the bubble, but + // we get called before that's happened. + Task* task = first_run_bubble_.NewRunnableMethod( + &LocationBarViewMac::ShowFirstRunBubbleInternal, bubble_type); + MessageLoop::current()->PostTask(FROM_HERE, task); +} + +void LocationBarViewMac::ShowFirstRunBubbleInternal( + FirstRun::BubbleType bubble_type) { + if (!field_ || ![field_ window]) + return; + + // The bubble needs to be just below the Omnibox and slightly to the right + // of the left omnibox icon, so shift x and y co-ordinates. + const NSPoint kOffset = NSMakePoint(-18, 4); + [FirstRunBubbleController showForView:field_ offset:kOffset profile:profile_]; +} + std::wstring LocationBarViewMac::GetInputString() const { return location_input_; } @@ -888,9 +909,9 @@ void LocationBarViewMac::ContentSettingImageView::OnMousePressed(NSRect bounds) ContentSettingBubbleModel::CreateContentSettingBubbleModel( tabContents, profile_, content_setting_image_model_->get_content_settings_type()); - [[ContentBlockedBubbleController showForModel:model + [ContentBlockedBubbleController showForModel:model parentWindow:window - anchoredAt:anchor] showWindow:nil]; + anchoredAt:anchor]; } NSString* LocationBarViewMac::ContentSettingImageView::GetToolTip() { diff --git a/chrome/browser/first_run_mac.mm b/chrome/browser/first_run_mac.mm index 4d2d29f..a9c5d21 100644 --- a/chrome/browser/first_run_mac.mm +++ b/chrome/browser/first_run_mac.mm @@ -70,10 +70,8 @@ FirstRunController::FirstRunController() void FirstRunController::FirstRunDone() { // Set preference to show first run bubble and welcome page. - // TODO(jeremy): Implement - // FirstRun::SetShowFirstRunBubblePref(true); - // FirstRun::SetShowWelcomePagePref(); - delete this; + FirstRun::SetShowFirstRunBubblePref(true); + FirstRun::SetShowWelcomePagePref(); } bool FirstRunController::DoFirstRun(Profile* profile, @@ -151,6 +149,9 @@ bool FirstRunController::DoFirstRun(Profile* profile, ignore_result(gc.release()); StartImportingWithUI(nil, items, importer_host_.get(), source_profile, profile, this, true); + } else { + // This is called by the importer if it runs. + FirstRunDone(); } return true; diff --git a/chrome/browser/gtk/first_run_bubble.cc b/chrome/browser/gtk/first_run_bubble.cc index e86df98..e169aca 100644 --- a/chrome/browser/gtk/first_run_bubble.cc +++ b/chrome/browser/gtk/first_run_bubble.cc @@ -12,7 +12,7 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/options_window.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/search_engines/util.h" #include "chrome/common/notification_service.h" #include "gfx/gtk_util.h" #include "grit/chromium_strings.h" @@ -28,19 +28,6 @@ const int kButtonPadding = 4; // Padding between content and edge of info bubble. const int kContentBorder = 7; - -string16 GetDefaultSearchEngineName(Profile* profile) { - if (!profile) { - NOTREACHED(); - return string16(); - } - const TemplateURL* const default_provider = - profile->GetTemplateURLModel()->GetDefaultSearchProvider(); - if (!default_provider) { - return string16(); - } - return WideToUTF16(default_provider->short_name()); -} } // namespace // static diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h index 412adf0..da87cdc 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.h +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -392,7 +392,7 @@ class LocationBarViewGtk : public AutocompleteEditController, // The transition type to use for the navigation. PageTransition::Type transition_; - // Used schedule a task for the first run info bubble. + // Used to schedule a task for the first run info bubble. ScopedRunnableMethodFactory<LocationBarViewGtk> first_run_bubble_; // When true, the location bar view is read only and also is has a slightly diff --git a/chrome/browser/search_engines/util.cc b/chrome/browser/search_engines/util.cc new file mode 100644 index 0000000..28e1c93 --- /dev/null +++ b/chrome/browser/search_engines/util.cc @@ -0,0 +1,25 @@ +// 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/search_engines/util.h" + +#include "base/utf_string_conversions.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/profile.h" + +string16 GetDefaultSearchEngineName(Profile* profile) { + if (!profile) { + NOTREACHED(); + return string16(); + } + const TemplateURL* const default_provider = + profile->GetTemplateURLModel()->GetDefaultSearchProvider(); + if (!default_provider) { + // TODO(cpu): bug 1187517. It is possible to have no default provider. + // returning an empty string is a stopgap measure for the crash + // http://code.google.com/p/chromium/issues/detail?id=2573 + return string16(); + } + return WideToUTF16(default_provider->short_name()); +} diff --git a/chrome/browser/search_engines/util.h b/chrome/browser/search_engines/util.h new file mode 100644 index 0000000..07f059c --- /dev/null +++ b/chrome/browser/search_engines/util.h @@ -0,0 +1,18 @@ +// 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. + +#ifndef CHROME_BROWSER_SEARCH_ENGINES_UTIL_H_ +#define CHROME_BROWSER_SEARCH_ENGINES_UTIL_H_ + +// This file contains utility functions for search engine functionality. + +#include "base/string16.h" + +class Profile; + +// Returns the short name of the default search engine, or the empty string if +// none is set. |profile| may be NULL. +string16 GetDefaultSearchEngineName(Profile* profile); + +#endif // CHROME_BROWSER_SEARCH_ENGINES_UTIL_H_ diff --git a/chrome/browser/views/first_run_bubble.cc b/chrome/browser/views/first_run_bubble.cc index 2c6bcf9..0ebc0c7 100644 --- a/chrome/browser/views/first_run_bubble.cc +++ b/chrome/browser/views/first_run_bubble.cc @@ -8,14 +8,14 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/win_util.h" +#include "base/utf_string_conversions.h" #include "base/win_util.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/first_run.h" #include "chrome/browser/options_window.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/browser/search_engines/util.h" #include "chrome/browser/metrics/user_metrics.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -46,22 +46,6 @@ const int kStringSeparationPadding = 2; // Margin around close button. const int kMarginRightOfCloseButton = 7; -std::wstring GetDefaultSearchEngineName(Profile* profile) { - if (!profile) { - NOTREACHED(); - return std::wstring(); - } - const TemplateURL* const default_provider = - profile->GetTemplateURLModel()->GetDefaultSearchProvider(); - if (!default_provider) { - // TODO(cpu): bug 1187517. It is possible to have no default provider. - // returning an empty string is a stopgap measure for the crash - // http://code.google.com/p/chromium/issues/detail?id=2573 - return std::wstring(); - } - return default_provider->short_name(); -} - } // namespace // Base class for implementations of the client view which appears inside the @@ -133,7 +117,7 @@ FirstRunBubbleView::FirstRunBubbleView(FirstRunBubble* bubble_window, AddChildView(label2_); std::wstring question_str = l10n_util::GetStringF(IDS_FR_BUBBLE_QUESTION, - GetDefaultSearchEngineName(profile)); + UTF16ToWideHack(GetDefaultSearchEngineName(profile))); label3_ = new views::Label(question_str); label3_->SetMultiLine(true); label3_->SetFont(font); @@ -142,7 +126,7 @@ FirstRunBubbleView::FirstRunBubbleView(FirstRunBubble* bubble_window, AddChildView(label3_); std::wstring keep_str = l10n_util::GetStringF(IDS_FR_BUBBLE_OK, - GetDefaultSearchEngineName(profile)); + UTF16ToWideHack(GetDefaultSearchEngineName(profile))); keep_button_ = new views::NativeButton(this, keep_str); keep_button_->SetIsDefault(true); AddChildView(keep_button_); @@ -421,7 +405,7 @@ FirstRunMinimalBubbleView::FirstRunMinimalBubbleView( ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont); label1_ = new views::Label(l10n_util::GetStringF(IDS_FR_SE_BUBBLE_TITLE, - GetDefaultSearchEngineName(profile_))); + UTF16ToWideHack(GetDefaultSearchEngineName(profile_)))); label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); AddChildView(label1_); diff --git a/chrome/browser/views/location_bar/location_bar_view.h b/chrome/browser/views/location_bar/location_bar_view.h index 2419468..538f1ba 100644 --- a/chrome/browser/views/location_bar/location_bar_view.h +++ b/chrome/browser/views/location_bar/location_bar_view.h @@ -356,7 +356,7 @@ class LocationBarView : public LocationBar, // focused. Used when the toolbar is in full keyboard accessibility mode. bool show_focus_rect_; - // Used schedule a task for the first run info bubble. + // Used to schedule a task for the first run info bubble. ScopedRunnableMethodFactory<LocationBarView> first_run_bubble_; DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarView); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index ec70636..5c5946e 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -586,6 +586,8 @@ 'browser/cocoa/background_gradient_view.mm', 'browser/cocoa/background_tile_view.h', 'browser/cocoa/background_tile_view.mm', + 'browser/cocoa/base_bubble_controller.h', + 'browser/cocoa/base_bubble_controller.mm', 'browser/cocoa/base_view.h', 'browser/cocoa/base_view.mm', 'browser/cocoa/browser_window_factory.mm', @@ -745,6 +747,8 @@ 'browser/cocoa/find_bar_view.mm', 'browser/cocoa/find_pasteboard.h', 'browser/cocoa/find_pasteboard.mm', + 'browser/cocoa/first_run_bubble_controller.h', + 'browser/cocoa/first_run_bubble_controller.mm', 'browser/cocoa/first_run_dialog.h', 'browser/cocoa/first_run_dialog.mm', 'browser/cocoa/floating_bar_backing_view.h', @@ -2089,6 +2093,8 @@ 'browser/search_engines/template_url_prepopulate_data.h', 'browser/search_engines/template_url_table_model.cc', 'browser/search_engines/template_url_table_model.h', + 'browser/search_engines/util.cc', + 'browser/search_engines/util.h', 'browser/session_startup_pref.cc', 'browser/session_startup_pref.h', 'browser/sessions/base_session_service.cc', @@ -2927,6 +2933,7 @@ 'app/nibs/ExtensionInstalledBubble.xib', 'app/nibs/ExtensionInstallPrompt.xib', 'app/nibs/ExtensionInstallPromptNoWarnings.xib', + 'app/nibs/FirstRunBubble.xib', 'app/nibs/FirstRunDialog.xib', 'app/nibs/FontLanguageSettings.xib', 'app/nibs/GeolocationExceptionsWindow.xib', diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index cb91f9a..b7dfcb6 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -222,6 +222,7 @@ 'app/nibs/ExtensionInstallPrompt.xib', 'app/nibs/ExtensionInstallPromptNoWarnings.xib', 'app/nibs/FindBar.xib', + 'app/nibs/FirstRunBubble.xib', 'app/nibs/FirstRunDialog.xib', 'app/nibs/FontLanguageSettings.xib', 'app/nibs/GeolocationExceptionsWindow.xib', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index bb49425..29c8b466 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -713,6 +713,7 @@ 'browser/cocoa/find_bar_text_field_unittest.mm', 'browser/cocoa/find_bar_view_unittest.mm', 'browser/cocoa/find_pasteboard_unittest.mm', + 'browser/cocoa/first_run_bubble_controller_unittest.mm', 'browser/cocoa/floating_bar_backing_view_unittest.mm', 'browser/cocoa/focus_tracker_unittest.mm', 'browser/cocoa/font_language_settings_controller_unittest.mm', |