summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-31 21:45:17 +0000
committermirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-31 21:45:17 +0000
commit54bc0925f6430d3fd94fbfc8cabff0a41128701a (patch)
tree0596552395a069054716171e111bb5c971367290
parent007cb731cd1d0af76a0688faa5d1e125c6f57db3 (diff)
downloadchromium_src-54bc0925f6430d3fd94fbfc8cabff0a41128701a.zip
chromium_src-54bc0925f6430d3fd94fbfc8cabff0a41128701a.tar.gz
chromium_src-54bc0925f6430d3fd94fbfc8cabff0a41128701a.tar.bz2
ExtensionInstalledBubble for Mac.
Adds ExtensionInstalledBubble.xib, which contains the framework for the bubble itself (icon view, close button, and three message fields). BUG= 26974 TEST= Install an extension. Bubble should show same information as windows bubble. Review URL: http://codereview.chromium.org/527012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37671 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd7
-rw-r--r--chrome/app/nibs/ExtensionInstalledBubble.xib685
-rw-r--r--chrome/browser/cocoa/autocomplete_text_field_cell.mm13
-rw-r--r--chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm7
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_bridge.h27
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_bridge.mm25
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller.h99
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller.mm343
-rw-r--r--chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm201
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.h3
-rw-r--r--chrome/browser/cocoa/extensions/browser_actions_controller.mm9
-rw-r--r--chrome/browser/cocoa/location_bar_view_mac.h29
-rw-r--r--chrome/browser/cocoa/location_bar_view_mac.mm65
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h3
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm8
-rw-r--r--chrome/browser/extensions/extension_install_ui.cc43
-rw-r--r--chrome/browser/extensions/extension_install_ui.h6
-rw-r--r--chrome/browser/tab_contents/infobar_delegate.h2
-rwxr-xr-xchrome/chrome_browser.gypi5
-rw-r--r--chrome/chrome_dll.gypi1
-rwxr-xr-xchrome/chrome_tests.gypi1
21 files changed, 1566 insertions, 16 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 58f2c95..274aecd 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2907,7 +2907,7 @@ each locale. -->
<!-- Extension installed bubble -->
<message name="IDS_EXTENSION_INSTALLED_HEADING" desc="First line in the content area of the extension installed bubble. Instructs that the extension was installed.">
- <ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph> is now installed
+ <ph name="EXTENSION_NAME">$1<ex>Gmail Checker</ex></ph> is now installed.
</message>
<message name="IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO" desc="Text displayed in the InfoBubble which explains that the UI of this extension is a Page Action icon which may appear for some pages.">
@@ -2917,9 +2917,12 @@ each locale. -->
<message name="IDS_MANAGE_EXTENSIONS" desc="The 'Manage Extensions...' text in the context menu for when right-clicking on extension icons">
Manage extensions...
</message>
- <message name="IDS_EXTENSION_INSTALLED_MANAGE_INFO" desc="Text displayed in the InfoBubble with instructives on how to find the chrome://extensions/ management page">
+ <message name="IDS_EXTENSION_INSTALLED_MANAGE_INFO" desc="Text displayed in the InfoBubble with instructions on how to find the chrome://extensions/ management page">
You can manage your installed extensions by clicking Extensions in the Tools menu.
</message>
+ <message name="IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC" desc="Text displayed in the InfoBubble with instructions on how to find the chrome://extensions/ management page on MAC OS X">
+ You can manage your installed extensions by clicking Extensions in the Window menu.
+ </message>
<!-- chrome://extensions page -->
<message name="IDS_EXTENSIONS_DEVELOPER_MODE_LINK" desc="Text of the link for developer mode.">
diff --git a/chrome/app/nibs/ExtensionInstalledBubble.xib b/chrome/app/nibs/ExtensionInstalledBubble.xib
new file mode 100644
index 0000000..709f8a6
--- /dev/null
+++ b/chrome/app/nibs/ExtensionInstalledBubble.xib
@@ -0,0 +1,685 @@
+<?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">677</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="1"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilderKit</string>
+ <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">ExtensionInstalledBubbleController</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="NSCustomObject" id="496862111">
+ <string key="NSClassName">ChromeUILocalizer</string>
+ </object>
+ <object class="NSCustomObject" id="613590598">
+ <string key="NSClassName">GTMUILocalizerAndLayoutTweaker</string>
+ </object>
+ <object class="NSWindowTemplate" id="602262820">
+ <int key="NSWindowStyleMask">15</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{196, 383}, {373, 127}}</string>
+ <int key="NSWTFlags">603982848</int>
+ <string key="NSWindowTitle">Window</string>
+ <string key="NSWindowClass">InfoBubbleWindow</string>
+ <nil key="NSViewClass"/>
+ <object class="NSView" key="NSWindowView" id="177257090">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomView" id="914312036">
+ <reference key="NSNextResponder" ref="177257090"/>
+ <int key="NSvFlags">301</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextField" id="480350025">
+ <reference key="NSNextResponder" ref="914312036"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{71, 20}, {261, 17}}</string>
+ <reference key="NSSuperview" ref="914312036"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="353810369">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272662528</int>
+ <string key="NSContents">^IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC</string>
+ <object class="NSFont" key="NSSupport" id="472995141">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">1.300000e+01</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="480350025"/>
+ <object class="NSColor" key="NSBackgroundColor" id="951604798">
+ <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="121031723">
+ <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="531091173">
+ <reference key="NSNextResponder" ref="914312036"/>
+ <int key="NSvFlags">-2147483380</int>
+ <string key="NSFrame">{{71, 56}, {261, 17}}</string>
+ <reference key="NSSuperview" ref="914312036"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="226927715">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272662528</int>
+ <string key="NSContents">^IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO</string>
+ <reference key="NSSupport" ref="472995141"/>
+ <reference key="NSControlView" ref="531091173"/>
+ <reference key="NSBackgroundColor" ref="951604798"/>
+ <reference key="NSTextColor" ref="121031723"/>
+ </object>
+ </object>
+ <object class="NSTextField" id="164174016">
+ <reference key="NSNextResponder" ref="914312036"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{71, 90}, {261, 17}}</string>
+ <reference key="NSSuperview" ref="914312036"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="993927473">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">272662528</int>
+ <string key="NSContents">^IDS_EXTENSION_INSTALLED_HEADING</string>
+ <reference key="NSSupport" ref="472995141"/>
+ <reference key="NSControlView" ref="164174016"/>
+ <reference key="NSBackgroundColor" ref="951604798"/>
+ <reference key="NSTextColor" ref="121031723"/>
+ </object>
+ </object>
+ <object class="NSButton" id="433090690">
+ <reference key="NSNextResponder" ref="914312036"/>
+ <int key="NSvFlags">265</int>
+ <string key="NSFrame">{{347, 94}, {16, 16}}</string>
+ <reference key="NSSuperview" ref="914312036"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="2621715">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134250496</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="472995141"/>
+ <reference key="NSControlView" ref="433090690"/>
+ <int key="NSButtonFlags">139215103</int>
+ <int key="NSButtonFlags2">6</int>
+ <object class="NSCustomResource" key="NSNormalImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">close_bar</string>
+ </object>
+ <object class="NSCustomResource" key="NSAlternateImage">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">close_bar_p</string>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <object class="NSImageView" id="967660638">
+ <reference key="NSNextResponder" ref="914312036"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableSet" key="NSDragTypes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="set.sortedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>Apple PDF pasteboard type</string>
+ <string>Apple PICT pasteboard type</string>
+ <string>Apple PNG pasteboard type</string>
+ <string>NSFilenamesPboardType</string>
+ <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
+ <string>NeXT TIFF v4.0 pasteboard type</string>
+ </object>
+ </object>
+ <string key="NSFrame">{{15, 66}, {43, 43}}</string>
+ <reference key="NSSuperview" ref="914312036"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSImageCell" key="NSCell" id="625965280">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">33554432</int>
+ <int key="NSAlign">0</int>
+ <int key="NSScale">0</int>
+ <int key="NSStyle">0</int>
+ <bool key="NSAnimates">NO</bool>
+ </object>
+ <bool key="NSEditable">YES</bool>
+ </object>
+ </object>
+ <string key="NSFrameSize">{373, 127}</string>
+ <reference key="NSSuperview" ref="177257090"/>
+ <string key="NSClassName">InfoBubbleView</string>
+ </object>
+ </object>
+ <string key="NSFrameSize">{373, 127}</string>
+ <reference key="NSSuperview"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {2560, 1578}}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</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">delegate</string>
+ <reference key="source" ref="602262820"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">7</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="602262820"/>
+ </object>
+ <int key="connectionID">8</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">localizer_</string>
+ <reference key="source" ref="613590598"/>
+ <reference key="destination" ref="496862111"/>
+ </object>
+ <int key="connectionID">9</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">iconImage_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="967660638"/>
+ </object>
+ <int key="connectionID">20</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">closeButton_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="433090690"/>
+ </object>
+ <int key="connectionID">30</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">extensionInstalledInfoMsg_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="480350025"/>
+ </object>
+ <int key="connectionID">39</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">extensionInstalledMsg_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="164174016"/>
+ </object>
+ <int key="connectionID">40</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">pageActionInfoMsg_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="531091173"/>
+ </object>
+ <int key="connectionID">42</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">closeWindow:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="433090690"/>
+ </object>
+ <int key="connectionID">43</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">infoBubbleView_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="914312036"/>
+ </object>
+ <int key="connectionID">45</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">uiObject_</string>
+ <reference key="source" ref="613590598"/>
+ <reference key="destination" ref="914312036"/>
+ </object>
+ <int key="connectionID">46</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="602262820"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="177257090"/>
+ </object>
+ <reference key="parent" ref="1002"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="177257090"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="914312036"/>
+ </object>
+ <reference key="parent" ref="602262820"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">3</int>
+ <reference key="object" ref="496862111"/>
+ <reference key="parent" ref="1002"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">4</int>
+ <reference key="object" ref="613590598"/>
+ <reference key="parent" ref="1002"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">44</int>
+ <reference key="object" ref="914312036"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="531091173"/>
+ <reference ref="164174016"/>
+ <reference ref="967660638"/>
+ <reference ref="433090690"/>
+ <reference ref="480350025"/>
+ </object>
+ <reference key="parent" ref="177257090"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">37</int>
+ <reference key="object" ref="480350025"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="353810369"/>
+ </object>
+ <reference key="parent" ref="914312036"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">38</int>
+ <reference key="object" ref="353810369"/>
+ <reference key="parent" ref="480350025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">35</int>
+ <reference key="object" ref="531091173"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="226927715"/>
+ </object>
+ <reference key="parent" ref="914312036"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">36</int>
+ <reference key="object" ref="226927715"/>
+ <reference key="parent" ref="531091173"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">33</int>
+ <reference key="object" ref="164174016"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="993927473"/>
+ </object>
+ <reference key="parent" ref="914312036"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">34</int>
+ <reference key="object" ref="993927473"/>
+ <reference key="parent" ref="164174016"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">15</int>
+ <reference key="object" ref="433090690"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="2621715"/>
+ </object>
+ <reference key="parent" ref="914312036"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">16</int>
+ <reference key="object" ref="2621715"/>
+ <reference key="parent" ref="433090690"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">18</int>
+ <reference key="object" ref="967660638"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="625965280"/>
+ </object>
+ <reference key="parent" ref="914312036"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="625965280"/>
+ <reference key="parent" ref="967660638"/>
+ </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.IBViewEditorWindowController.showingBoundsRectangles</string>
+ <string>1.IBViewEditorWindowController.showingLayoutRectangles</string>
+ <string>1.IBWindowTemplateEditedContentRect</string>
+ <string>1.NSWindowTemplate.visibleAtLaunch</string>
+ <string>15.CustomClassName</string>
+ <string>15.IBPluginDependency</string>
+ <string>16.IBPluginDependency</string>
+ <string>18.IBPluginDependency</string>
+ <string>19.IBPluginDependency</string>
+ <string>2.IBAttributePlaceholdersKey</string>
+ <string>2.IBPluginDependency</string>
+ <string>2.IBUserGuides</string>
+ <string>3.IBPluginDependency</string>
+ <string>33.IBPluginDependency</string>
+ <string>34.IBPluginDependency</string>
+ <string>35.IBPluginDependency</string>
+ <string>36.IBPluginDependency</string>
+ <string>37.IBPluginDependency</string>
+ <string>38.IBPluginDependency</string>
+ <string>4.IBPluginDependency</string>
+ <string>44.IBPluginDependency</string>
+ <string>44.IBUserGuides</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilderKit</string>
+ <string>com.apple.InterfaceBuilderKit</string>
+ <string>{{1120, 881}, {373, 127}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <boolean value="NO" id="6"/>
+ <reference ref="6"/>
+ <string>{{1120, 881}, {373, 127}}</string>
+ <reference ref="6"/>
+ <string>HoverCloseButton</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 class="NSMutableDictionary">
+ <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>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSMutableArray">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <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>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSMutableArray">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUserGuide">
+ <reference key="view" ref="914312036"/>
+ <float key="location">8.000000e+00</float>
+ <int key="affinity">3</int>
+ </object>
+ </object>
+ </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">46</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <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">ExtensionInstalledBubbleController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>closeWindow:</string>
+ <string>showWindow:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>closeButton_</string>
+ <string>extensionInstalledInfoMsg_</string>
+ <string>extensionInstalledMsg_</string>
+ <string>iconImage_</string>
+ <string>infoBubbleView_</string>
+ <string>pageActionInfoMsg_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>HoverCloseButton</string>
+ <string>NSTextField</string>
+ <string>NSTextField</string>
+ <string>NSImageView</string>
+ <string>InfoBubbleView</string>
+ <string>NSTextField</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/extension_installed_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">HoverCloseButton</string>
+ <string key="superclassName">NSButton</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/hover_close_button.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">NSWindow</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">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/nswindow_local_state.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/autocomplete_text_field_cell.mm b/chrome/browser/cocoa/autocomplete_text_field_cell.mm
index 8f54193..654742b 100644
--- a/chrome/browser/cocoa/autocomplete_text_field_cell.mm
+++ b/chrome/browser/cocoa/autocomplete_text_field_cell.mm
@@ -307,7 +307,12 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
LocationBarViewMac::PageActionImageView* view =
page_action_views_->ViewAt(index);
const NSImage* icon = view->GetImage();
- if (!icon || !view->IsVisible()) {
+
+ // If we are calculating space for a preview page action, the icon is still
+ // loading. We use this function only to get the correct x value for the
+ // extension installed bubble arrow.
+ if (!view->preview_enabled() &&
+ (!icon || !view->IsVisible())) {
return NSZeroRect;
}
@@ -333,7 +338,11 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) {
}
widthUsed += kIconHorizontalPad;
- return [self rightJustifyImage:[icon size]
+ // If we are calculating frame space for a preview, the icon is still
+ // loading -- use maximum size as a placeholder.
+ NSSize iconSize = view->GetImageSize();
+
+ return [self rightJustifyImage:iconSize
inRect:cellFrame
withMargin:widthUsed];
}
diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm
index 56ab1f5..b1610b3 100644
--- a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm
+++ b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm
@@ -371,6 +371,13 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) {
EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:0 inFrame:bounds]));
EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:1 inFrame:bounds]));
+ // Test preview page actions, as used by the extension installed bubble.
+ TestPageActionImageView preview_view;
+ list.Add(&preview_view);
+ EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:2 inFrame:bounds]));
+ preview_view.set_preview_enabled(true);
+ EXPECT_FALSE(NSIsEmptyRect([cell pageActionFrameForIndex:2 inFrame:bounds]));
+
// One page action, no security icon.
page_action_view.SetVisible(true);
NSRect iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds];
diff --git a/chrome/browser/cocoa/extension_installed_bubble_bridge.h b/chrome/browser/cocoa/extension_installed_bubble_bridge.h
new file mode 100644
index 0000000..7f933f3
--- /dev/null
+++ b/chrome/browser/cocoa/extension_installed_bubble_bridge.h
@@ -0,0 +1,27 @@
+// 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.
+
+// C++ bridge function to connect ExtensionInstallUI to the Cocoa-based
+// extension installed bubble.
+
+#ifndef CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
+#define CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
+
+#include "app/gfx/native_widget_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Browser;
+class Extension;
+
+namespace ExtensionInstalledBubbleCocoa {
+
+// This function is called by the ExtensionInstallUI when an extension has been
+// installed.
+void ShowExtensionInstalledBubble(gfx::NativeWindow window,
+ Extension* extension,
+ Browser* browser,
+ SkBitmap icon);
+}
+
+#endif // CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_BRIDGE_H_
diff --git a/chrome/browser/cocoa/extension_installed_bubble_bridge.mm b/chrome/browser/cocoa/extension_installed_bubble_bridge.mm
new file mode 100644
index 0000000..e43b956
--- /dev/null
+++ b/chrome/browser/cocoa/extension_installed_bubble_bridge.mm
@@ -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.
+
+#import <Cocoa/Cocoa.h>
+
+#import "extension_installed_bubble_bridge.h"
+
+#include "chrome/browser/browser.h"
+#import "chrome/browser/cocoa/extension_installed_bubble_controller.h"
+#include "chrome/common/extensions/extension.h"
+
+void ExtensionInstalledBubbleCocoa::ShowExtensionInstalledBubble(
+ gfx::NativeWindow window,
+ Extension* extension,
+ Browser* browser,
+ SkBitmap icon) {
+ // The controller is deallocated when the window is closed, so no need to
+ // worry about it here.
+ [[ExtensionInstalledBubbleController alloc]
+ initWithParentWindow:window
+ extension:extension
+ browser:browser
+ icon:icon];
+}
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.h b/chrome/browser/cocoa/extension_installed_bubble_controller.h
new file mode 100644
index 0000000..880db3f
--- /dev/null
+++ b/chrome/browser/cocoa/extension_installed_bubble_controller.h
@@ -0,0 +1,99 @@
+// 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_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
+
+#import <Cocoa/Cocoa.h>
+#import "base/cocoa_protocols_mac.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/cocoa/browser_window_controller.h"
+#import "chrome/browser/cocoa/info_bubble_view.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+class Browser;
+class Extension;
+class ExtensionLoadedNotificationObserver;
+
+@class HoverCloseButton;
+
+namespace extension_installed_bubble {
+
+// Maximum height or width of extension's icon (corresponds to Windows & GTK).
+const int kIconSize = 43;
+
+// Outer vertical margin for text, icon, and closing x.
+const int kOuterVerticalMargin = 15;
+
+// Inner vertical margin for text messages.
+const int kInnerVerticalMargin = 10;
+
+// We use a different kind of notification for each of these extension types.
+typedef enum {
+ kBrowserAction,
+ kPageAction,
+ kGeneric
+} ExtensionType;
+
+}
+
+// Controller for the extension installed bubble. This bubble pops up after
+// an extension has been installed to inform the user that the install happened
+// properly, and to let the user know how to manage this extension in the
+// future.
+@interface ExtensionInstalledBubbleController :
+ NSWindowController<NSWindowDelegate> {
+ @private
+ NSWindow* parentWindow_; // weak
+ Extension* extension_; // weak
+ Browser* browser_; // weak
+ scoped_nsobject<NSImage> icon_;
+
+ extension_installed_bubble::ExtensionType type_;
+
+ // Lets us register for EXTENSION_LOADED notifications. The actual
+ // notifications are sent to the observer object, which proxies them
+ // back to the controller.
+ scoped_ptr<ExtensionLoadedNotificationObserver> extensionObserver_;
+
+ // References below are weak, being obtained from the nib.
+ IBOutlet InfoBubbleView* infoBubbleView_;
+ IBOutlet HoverCloseButton* closeButton_;
+ IBOutlet NSImageView* iconImage_;
+ IBOutlet NSTextField* extensionInstalledMsg_;
+ IBOutlet NSTextField* pageActionInfoMsg_; // Only shown for page actions.
+ IBOutlet NSTextField* extensionInstalledInfoMsg_;
+}
+
+@property (readonly) Extension* extension;
+
+// Initialize the window, and then create observers to wait for the extension
+// to complete loading, or the browser window to close.
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ extension:(Extension*)extension
+ browser:(Browser*)browser
+ icon:(SkBitmap)icon;
+
+// Action for close button.
+- (IBAction)closeWindow:(id)sender;
+
+// Displays the extension installed bubble. This callback is triggered by
+// the extensionObserver when the extension has completed loading.
+- (void)showWindow:(id)sender;
+
+@end
+
+@interface ExtensionInstalledBubbleController(ExposedForTesting)
+
+- (void)removePageActionPreview;
+- (NSWindow*)initializeWindow;
+- (int)calculateWindowHeight;
+- (void)setMessageFrames:(int)newWindowHeight;
+- (NSRect)getExtensionInstalledMsgFrame;
+- (NSRect)getPageActionInfoMsgFrame;
+- (NSRect)getExtensionInstalledInfoMsgFrame;
+
+@end // ExtensionInstalledBubbleController(ExposedForTesting)
+
+#endif // CHROME_BROWSER_COCOA_EXTENSION_INSTALLED_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller.mm b/chrome/browser/cocoa/extension_installed_bubble_controller.mm
new file mode 100644
index 0000000..eba39e4
--- /dev/null
+++ b/chrome/browser/cocoa/extension_installed_bubble_controller.mm
@@ -0,0 +1,343 @@
+// 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 "extension_installed_bubble_controller.h"
+
+#include "app/l10n_util.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/cocoa/autocomplete_text_field_cell.h"
+#include "chrome/browser/cocoa/browser_window_cocoa.h"
+#include "chrome/browser/cocoa/browser_window_controller.h"
+#include "chrome/browser/cocoa/extensions/browser_actions_controller.h"
+#include "chrome/browser/cocoa/hover_close_button.h"
+#include "chrome/browser/cocoa/info_bubble_view.h"
+#include "chrome/browser/cocoa/location_bar_view_mac.h"
+#include "chrome/browser/cocoa/toolbar_controller.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+#import "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMUILocalizerAndLayoutTweaker.h"
+
+
+
+// C++ class that receives EXTENSION_LOADED notifications and proxies them back
+// to |controller|.
+class ExtensionLoadedNotificationObserver : public NotificationObserver {
+ public:
+ ExtensionLoadedNotificationObserver(
+ ExtensionInstalledBubbleController* controller)
+ : controller_(controller) {
+ // Create a registrar and add ourselves to it.
+ registrar_.Add(this, NotificationType::EXTENSION_LOADED,
+ NotificationService::AllSources());
+ }
+
+ private:
+ // NotificationObserver implementation. Tells the controller to start showing
+ // its window on the main thread when the extension has finished loading.
+ void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NotificationType::EXTENSION_LOADED) {
+ Extension* extension = Details<Extension>(details).ptr();
+ if (extension == [controller_ extension]) {
+ [controller_ performSelectorOnMainThread:@selector(showWindow:)
+ withObject:controller_
+ waitUntilDone:NO];
+ }
+ } else {
+ NOTREACHED() << "Received unexpected notification.";
+ }
+ }
+
+ NotificationRegistrar registrar_;
+ ExtensionInstalledBubbleController* controller_; // weak, owns us
+};
+
+@implementation ExtensionInstalledBubbleController
+
+@synthesize extension = extension_;
+
+- (id)initWithParentWindow:(NSWindow*)parentWindow
+ extension:(Extension*)extension
+ browser:(Browser*)browser
+ icon:(SkBitmap)icon {
+ NSString* nibPath =
+ [mac_util::MainAppBundle() pathForResource:@"ExtensionInstalledBubble"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
+ parentWindow_ = parentWindow;
+ extension_ = extension;
+ browser_ = browser;
+ icon_.reset([gfx::SkBitmapToNSImage(icon) retain]);
+
+ if (extension->browser_action()) {
+ type_ = extension_installed_bubble::kBrowserAction;
+ } else if (extension->page_action() &&
+ !extension->page_action()->default_icon_path().empty()) {
+ type_ = extension_installed_bubble::kPageAction;
+ } else {
+ NOTREACHED(); // kGeneric installs handled in the extension_install_ui.
+ }
+
+ // Start showing window only after extension has fully loaded.
+ extensionObserver_.reset(new ExtensionLoadedNotificationObserver(self));
+
+ // Watch to see if the parent window closes, and close this one if so.
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ [center addObserver:self
+ selector:@selector(parentWindowWillClose:)
+ name:NSWindowWillCloseNotification
+ object:parentWindow_];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (void)close {
+ [parentWindow_ removeChildWindow:[self window]];
+ [super close];
+}
+
+- (void)parentWindowWillClose:(NSNotification*)notification {
+ [self close];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ // Turn off page action icon preview when the window closes.
+ if (extension_->page_action()) {
+ [self removePageActionPreview];
+ }
+ // We caught a close so we don't need to watch for the parent closing.
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self autorelease];
+}
+
+// The controller is the delegate of the window, so it receives "did resign
+// key" notifications. When key is resigned, close the window.
+- (void)windowDidResignKey:(NSNotification*)notification {
+ NSWindow* window = [self window];
+ DCHECK_EQ([notification object], window);
+ DCHECK([window isVisible]);
+ [self close];
+}
+
+- (IBAction)closeWindow:(id)sender {
+ DCHECK([[self window] isVisible]);
+ [self close];
+}
+
+// Extracted to a function here so that it can be overwritten for unit
+// testing.
+- (void)removePageActionPreview {
+ BrowserWindowCocoa* window = static_cast<BrowserWindowCocoa*>(
+ browser_->window());
+ LocationBarViewMac* locationBarView = static_cast<LocationBarViewMac*>(
+ [[window->cocoa_controller() toolbarController] locationBarBridge]);
+
+ locationBarView->SetPreviewEnabledPageAction(extension_->page_action(),
+ false); // disables preview.
+ [locationBarView->GetAutocompleteTextField() setNeedsDisplay:YES];
+}
+
+// The extension installed bubble points at the browser action icon or the
+// page action icon (shown as a preview), depending on the extension type.
+// We need to calculate the location of these icons and the size of the
+// message itself (which varies with the title of the extension) in order
+// to figure out the origin point for the extension installed bubble.
+// TODO(mirandac): add framework to easily test extension UI components!
+- (NSPoint)calculateArrowPoint {
+ BrowserWindowCocoa* window =
+ static_cast<BrowserWindowCocoa*>(browser_->window());
+ NSPoint arrowPoint;
+
+ switch(type_) {
+ case extension_installed_bubble::kBrowserAction: {
+ // Find the center of the bottom of the browser action icon.
+ NSView* button = [[[window->cocoa_controller() toolbarController]
+ browserActionsController] browserActionViewForExtension:extension_];
+ DCHECK(button);
+ NSRect boundsRect = [[[button window] contentView]
+ convertRect:[button frame]
+ fromView:[button superview]];
+ arrowPoint =
+ NSMakePoint(NSMinX(boundsRect) + NSWidth([button frame]) / 2,
+ NSMinY(boundsRect));
+ break;
+ }
+ case extension_installed_bubble::kPageAction: {
+ LocationBarViewMac* locationBarView =
+ static_cast<LocationBarViewMac*>(
+ [[window->cocoa_controller() toolbarController]
+ locationBarBridge]);
+ // Tell the location bar to show a preview of the page action icon, which
+ // would ordinarily only be displayed on a page of the appropriate type.
+ // We remove this preview when the extension installed bubble closes.
+ locationBarView->SetPreviewEnabledPageAction(extension_->page_action(),
+ true);
+
+ // Find the center of the bottom of the page action icon.
+ AutocompleteTextField* field =
+ locationBarView->GetAutocompleteTextField();
+ size_t index =
+ locationBarView->GetPageActionIndex(extension_->page_action());
+ NSView* browserContentWindow = [window->GetNativeHandle() contentView];
+ NSRect iconRect = [[field autocompleteTextFieldCell]
+ pageActionFrameForIndex:index inFrame:[field frame]];
+ NSRect boundsrect = [browserContentWindow convertRect:iconRect
+ fromView:[field superview]];
+ arrowPoint =
+ NSMakePoint(NSMinX(boundsrect) - NSWidth(boundsrect) / 2 - 1,
+ NSMinY(boundsrect));
+ break;
+ }
+ default: {
+ NOTREACHED() << "Generic extension type not allowed in install bubble.";
+ }
+ }
+ return arrowPoint;
+}
+
+// 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 {
+ // Generic extensions get an infobar rather than a bubble.
+ DCHECK(type_ != extension_installed_bubble::kGeneric);
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ // Load nib and calculate height based on messages to be shown.
+ NSWindow* window = [self initializeWindow];
+ int newWindowHeight = [self calculateWindowHeight];
+ NSSize windowDelta = NSMakeSize(
+ 0, newWindowHeight - NSHeight([[window contentView] bounds]));
+ [infoBubbleView_ setFrameSize:NSMakeSize(
+ NSWidth([[window contentView] bounds]), newWindowHeight)];
+ NSRect newFrame = [window frame];
+ newFrame.size.height += windowDelta.height;
+ [window setFrame:newFrame display:NO];
+
+ // Now that we have resized the window, adjust y pos of the messages.
+ [self setMessageFrames:newWindowHeight];
+
+ // Find window origin, taking into account bubble size and arrow location.
+ NSPoint origin =
+ [parentWindow_ convertBaseToScreen:[self calculateArrowPoint]];
+ origin.x -= NSWidth([window frame]) - kBubbleArrowXOffset -
+ kBubbleArrowWidth / 2;
+ origin.y -= NSHeight([window frame]);
+ [window setFrameOrigin:origin];
+
+ [parentWindow_ addChildWindow:window
+ ordered:NSWindowAbove];
+ [window makeKeyAndOrderFront:self];
+}
+
+// Finish nib loading, set arrow location and load icon into window. This
+// function is exposed for unit testing.
+- (NSWindow*)initializeWindow {
+ NSWindow* window = [self window]; // completes nib load
+ [infoBubbleView_ setArrowLocation:kTopRight];
+
+ // Set appropriate icon, resizing if necessary.
+ if ([icon_ size].width > extension_installed_bubble::kIconSize) {
+ [icon_ setSize:NSMakeSize(extension_installed_bubble::kIconSize,
+ extension_installed_bubble::kIconSize)];
+ }
+ [iconImage_ setImage:icon_];
+ [iconImage_ setNeedsDisplay:YES];
+ return window;
+ }
+
+// Calculate the height of each install message, resizing messages in their
+// frames to fit window width. Return the new window height, based on the
+// total of all message heights.
+- (int)calculateWindowHeight {
+ // Adjust the window height to reflect the sum height of all messages
+ // and vertical padding.
+ int newWindowHeight = 2 * extension_installed_bubble::kOuterVerticalMargin;
+
+ // First part of extension installed message.
+ [extensionInstalledMsg_ setStringValue:l10n_util::GetNSStringF(
+ IDS_EXTENSION_INSTALLED_HEADING, UTF8ToUTF16(extension_->name()))];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:extensionInstalledMsg_];
+ newWindowHeight += [extensionInstalledMsg_ frame].size.height +
+ extension_installed_bubble::kInnerVerticalMargin;
+
+ // If type is page action, include a special message about page actions.
+ if (type_ == extension_installed_bubble::kPageAction) {
+ [pageActionInfoMsg_ setHidden:NO];
+ [[pageActionInfoMsg_ cell]
+ setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:pageActionInfoMsg_];
+ newWindowHeight += [pageActionInfoMsg_ frame].size.height +
+ extension_installed_bubble::kInnerVerticalMargin;
+ }
+
+ // Second part of extension installed message.
+ [[extensionInstalledInfoMsg_ cell]
+ setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
+ [GTMUILocalizerAndLayoutTweaker
+ sizeToFitFixedWidthTextField:extensionInstalledInfoMsg_];
+ newWindowHeight += [extensionInstalledInfoMsg_ frame].size.height;
+
+ return newWindowHeight;
+}
+
+// Adjust y-position of messages to sit properly in new window height.
+- (void)setMessageFrames:(int)newWindowHeight {
+ // The extension messages will always be shown.
+ NSRect extensionMessageFrame1 = [extensionInstalledMsg_ frame];
+ NSRect extensionMessageFrame2 = [extensionInstalledInfoMsg_ frame];
+
+ extensionMessageFrame1.origin.y = newWindowHeight - (
+ extensionMessageFrame1.size.height +
+ extension_installed_bubble::kOuterVerticalMargin);
+ [extensionInstalledMsg_ setFrame:extensionMessageFrame1];
+ if (type_ == extension_installed_bubble::kPageAction) {
+ // The page action message is only shown when appropriate.
+ NSRect pageActionMessageFrame = [pageActionInfoMsg_ frame];
+ pageActionMessageFrame.origin.y = extensionMessageFrame1.origin.y - (
+ pageActionMessageFrame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ [pageActionInfoMsg_ setFrame:pageActionMessageFrame];
+ extensionMessageFrame2.origin.y = pageActionMessageFrame.origin.y - (
+ extensionMessageFrame2.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ } else {
+ extensionMessageFrame2.origin.y = extensionMessageFrame1.origin.y - (
+ extensionMessageFrame2.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ }
+ [extensionInstalledInfoMsg_ setFrame:extensionMessageFrame2];
+}
+
+// Exposed for unit testing.
+- (NSRect)getExtensionInstalledMsgFrame {
+ return [extensionInstalledMsg_ frame];
+}
+
+- (NSRect)getPageActionInfoMsgFrame {
+ return [pageActionInfoMsg_ frame];
+}
+
+- (NSRect)getExtensionInstalledInfoMsgFrame {
+ return [extensionInstalledInfoMsg_ frame];
+}
+
+@end
diff --git a/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm b/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
new file mode 100644
index 0000000..8f1d4d5
--- /dev/null
+++ b/chrome/browser/cocoa/extension_installed_bubble_controller_unittest.mm
@@ -0,0 +1,201 @@
+// 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>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_ptr.h"
+#import "chrome/browser/browser_window.h"
+#import "chrome/browser/cocoa/browser_test_helper.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/cocoa/extension_installed_bubble_controller.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "webkit/glue/image_decoder.h"
+
+// ExtensionInstalledBubbleController with removePageActionPreview overridden
+// to a no-op, because pageActions are not yet hooked up in the test browser.
+@interface ExtensionInstalledBubbleControllerForTest :
+ ExtensionInstalledBubbleController {
+ }
+
+ // Do nothing, because browser window is not set up with page actions
+ // for unit testing.
+- (void)removePageActionPreview;
+
+@end
+
+@implementation ExtensionInstalledBubbleControllerForTest
+
+ -(void)removePageActionPreview { }
+
+@end
+
+namespace keys = extension_manifest_keys;
+
+class ExtensionInstalledBubbleControllerTest : public CocoaTest {
+
+ public:
+ virtual void SetUp() {
+ CocoaTest::SetUp();
+ browser_ = helper_.browser();
+ window_ = helper_.CreateBrowserWindow()->GetNativeHandle();
+ icon_ = LoadTestIcon();
+ }
+
+ virtual void TearDown() {
+ helper_.CloseBrowserWindow();
+ CocoaTest::TearDown();
+ }
+
+ // Load test icon from extension test directory.
+ SkBitmap LoadTestIcon() {
+ FilePath path;
+ PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions").AppendASCII("icon1.png");
+
+ std::string file_contents;
+ file_util::ReadFileToString(path, &file_contents);
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(file_contents.data());
+
+ SkBitmap bitmap;
+ webkit_glue::ImageDecoder decoder;
+ bitmap = decoder.Decode(data, file_contents.length());
+
+ return bitmap;
+ }
+
+ // Create a skeletal framework of either page action or browser action
+ // type. This extension only needs to have a type and a name to initialize
+ // the ExtensionInstalledBubble for unit testing.
+ Extension* CreateExtension(extension_installed_bubble::ExtensionType type) {
+ FilePath path;
+ PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions").AppendASCII("dummy");
+
+ DictionaryValue extension_input_value;
+ extension_input_value.SetString(keys::kVersion, "1.0.0.0");
+ if (type == extension_installed_bubble::kPageAction) {
+ extension_input_value.SetString(keys::kName, "page action extension");
+ DictionaryValue* action = new DictionaryValue;
+ action->SetString(keys::kPageActionId, "ExtensionActionId");
+ action->SetString(keys::kPageActionDefaultTitle, "ExtensionActionTitle");
+ action->SetString(keys::kPageActionDefaultIcon, "image1.png");
+ ListValue* action_list = new ListValue;
+ action_list->Append(action);
+ extension_input_value.Set(keys::kPageActions, action_list);
+ } else {
+ extension_input_value.SetString(keys::kName, "browser action extension");
+ DictionaryValue* browser_action = new DictionaryValue;
+ // An empty dictionary is enough to create a Browser Action.
+ extension_input_value.Set(keys::kBrowserAction, browser_action);
+ }
+
+ Extension* extension = new Extension(path);
+ std::string error;
+ extension->InitFromValue(extension_input_value, false, &error);
+ return extension;
+ }
+
+ // Allows us to create the window and browser for testing.
+ BrowserTestHelper helper_;
+
+ // Required to initialize the extension installed bubble.
+ NSWindow* window_; // weak, owned by BrowserTestHelper.
+
+ // Required to initialize the extension installed bubble.
+ Browser* browser_; // weak, owned by BrowserTestHelper.
+
+ // The icon_ to be loaded into the bubble window.
+ SkBitmap icon_;
+};
+
+// Confirm that window sizes are set correctly for a page action extension.
+TEST_F(ExtensionInstalledBubbleControllerTest, PageActionTest) {
+ scoped_ptr<Extension> extension;
+ extension.reset(
+ CreateExtension(extension_installed_bubble::kPageAction));
+ ExtensionInstalledBubbleControllerForTest* controller =
+ [[ExtensionInstalledBubbleControllerForTest alloc]
+ initWithParentWindow:window_
+ extension:extension.get()
+ browser:browser_
+ icon:icon_];
+ EXPECT_TRUE(controller);
+
+ // Initialize window without having to calculate tabstrip locations.
+ [controller initializeWindow];
+ EXPECT_TRUE([controller window]);
+
+ int height = [controller calculateWindowHeight];
+ // Height should equal the vertical padding + height of all messages.
+ int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin +
+ 2 * extension_installed_bubble::kInnerVerticalMargin +
+ [controller getExtensionInstalledMsgFrame].size.height +
+ [controller getExtensionInstalledInfoMsgFrame].size.height +
+ [controller getPageActionInfoMsgFrame].size.height;
+ EXPECT_EQ(height, correctHeight);
+
+ [controller setMessageFrames:height];
+ NSRect msg3Frame = [controller getExtensionInstalledInfoMsgFrame];
+ // Bottom message should be kOuterVerticalMargin pixels above window edge.
+ EXPECT_EQ(msg3Frame.origin.y,
+ extension_installed_bubble::kOuterVerticalMargin);
+ NSRect msg2Frame = [controller getPageActionInfoMsgFrame];
+ // Pageaction message should be kInnerVerticalMargin pixels above bottom msg.
+ EXPECT_EQ(msg2Frame.origin.y,
+ msg3Frame.origin.y + msg3Frame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+ NSRect msg1Frame = [controller getExtensionInstalledMsgFrame];
+ // Top message should be kInnerVerticalMargin pixels above Pageaction msg.
+ EXPECT_EQ(msg1Frame.origin.y,
+ msg2Frame.origin.y + msg2Frame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+
+ [controller close];
+}
+
+TEST_F(ExtensionInstalledBubbleControllerTest, BrowserActionTest) {
+ scoped_ptr<Extension> extension;
+ extension.reset(
+ CreateExtension(extension_installed_bubble::kBrowserAction));
+ ExtensionInstalledBubbleControllerForTest* controller =
+ [[ExtensionInstalledBubbleControllerForTest alloc]
+ initWithParentWindow:window_
+ extension:extension.get()
+ browser:browser_
+ icon:icon_];
+ EXPECT_TRUE(controller);
+
+ // Initialize window without having to calculate tabstrip locations.
+ [controller initializeWindow];
+ EXPECT_TRUE([controller window]);
+
+ int height = [controller calculateWindowHeight];
+ // Height should equal the vertical padding + height of all messages.
+ int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin +
+ extension_installed_bubble::kInnerVerticalMargin +
+ [controller getExtensionInstalledMsgFrame].size.height +
+ [controller getExtensionInstalledInfoMsgFrame].size.height;
+ EXPECT_EQ(height, correctHeight);
+
+ [controller setMessageFrames:height];
+ NSRect msg3Frame = [controller getExtensionInstalledInfoMsgFrame];
+ // Bottom message should start kOuterVerticalMargin pixels above window edge.
+ EXPECT_EQ(msg3Frame.origin.y,
+ extension_installed_bubble::kOuterVerticalMargin);
+ NSRect msg1Frame = [controller getExtensionInstalledMsgFrame];
+ // Top message should start kInnerVerticalMargin pixels above top of
+ // extensionInstalled message, because page action message is hidden.
+ EXPECT_EQ(msg1Frame.origin.y,
+ msg3Frame.origin.y + msg3Frame.size.height +
+ extension_installed_bubble::kInnerVerticalMargin);
+
+ [controller close];
+}
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.h b/chrome/browser/cocoa/extensions/browser_actions_controller.h
index 97d5130..1d38da6 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.h
+++ b/chrome/browser/cocoa/extensions/browser_actions_controller.h
@@ -78,6 +78,9 @@ extern NSString* const kBrowserActionsChangedNotification;
// Executes the action designated by the extension.
- (void)browserActionClicked:(BrowserActionButton*)sender;
+// Returns the NSView for the action button associated with an extension.
+- (NSView*)browserActionViewForExtension:(Extension*)extension;
+
@end // @interface BrowserActionsController
@interface BrowserActionsController(TestingAPI)
diff --git a/chrome/browser/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
index e17f12d..3d5cad9 100644
--- a/chrome/browser/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/cocoa/extensions/browser_actions_controller.mm
@@ -280,6 +280,15 @@ class ExtensionsServiceObserverBridge : public NotificationObserver {
return selected_tab->controller().session_id().id();
}
+- (NSView*)browserActionViewForExtension:(Extension*)extension {
+ for (BrowserActionButton* button in buttonOrder_.get()) {
+ if ([button extension] == extension)
+ return button;
+ }
+ NOTREACHED();
+ return nil;
+}
+
- (NSButton*)buttonWithIndex:(int)index {
return [buttonOrder_ objectAtIndex:(NSUInteger)index];
}
diff --git a/chrome/browser/cocoa/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar_view_mac.h
index 2d82997..be784b5 100644
--- a/chrome/browser/cocoa/location_bar_view_mac.h
+++ b/chrome/browser/cocoa/location_bar_view_mac.h
@@ -62,7 +62,7 @@ class LocationBarViewMac : public AutocompleteEditController,
}
virtual LocationBarTesting* GetLocationBarForTesting() { return this; }
- // Overriden from LocationBarTesting:
+ // Overridden from LocationBarTesting:
virtual int PageActionCount();
virtual int PageActionVisibleCount();
virtual ExtensionAction* GetPageAction(size_t index);
@@ -74,6 +74,25 @@ class LocationBarViewMac : public AutocompleteEditController,
// saved state from the tab (for tab switching).
void Update(const TabContents* tab, bool should_restore_state);
+ // Sets preview_enabled_ for the PageActionImageView associated with this
+ // |page_action|. If |preview_enabled|, the location bar will display the
+ // PageAction icon even if it has not been activated by the extension.
+ // This is used by the ExtensionInstalledBubble to preview what the icon
+ // will look like for the user upon installation of the extension.
+ void SetPreviewEnabledPageAction(ExtensionAction* page_action,
+ bool preview_enabled);
+
+ // Return the index of a given page_action.
+ size_t GetPageActionIndex(ExtensionAction* page_action);
+
+ // PageActionImageView is nested in LocationBarViewMac, and only needed
+ // here so that we can access the icon of a page action when preview_enabled_
+ // has been set.
+ class PageActionImageView;
+
+ // Return the PageActionImageView associated with |page_action|.
+ PageActionImageView* GetPageActionImageView(ExtensionAction* page_action);
+
virtual void OnAutocompleteAccept(const GURL& url,
WindowOpenDisposition disposition,
PageTransition::Type transition,
@@ -188,6 +207,12 @@ class LocationBarViewMac : public AutocompleteEditController,
void set_preview_enabled(bool enabled) { preview_enabled_ = enabled; }
+ bool preview_enabled() { return preview_enabled_; }
+
+ // Return the size of the image, or a default size if no image available
+ // and preview is enabled.
+ virtual NSSize GetImageSize();
+
// Either notify listeners or show a popup depending on the Page Action.
// Virtual so it can be overridden for testing.
virtual bool OnMousePressed(NSRect bounds);
@@ -255,7 +280,7 @@ class LocationBarViewMac : public AutocompleteEditController,
scoped_nsobject<NSString> tooltip_;
// This is used for post-install visual feedback. The page_action icon
- // is briefly shown even if it hasn't been enabled by it's extension.
+ // is briefly shown even if it hasn't been enabled by its extension.
bool preview_enabled_;
// Used to register for notifications received by NotificationObserver.
diff --git a/chrome/browser/cocoa/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar_view_mac.mm
index 52a28b2..ec592cb 100644
--- a/chrome/browser/cocoa/location_bar_view_mac.mm
+++ b/chrome/browser/cocoa/location_bar_view_mac.mm
@@ -328,6 +328,54 @@ int LocationBarViewMac::PageActionVisibleCount() {
return static_cast<int>(page_action_views_->VisibleCount());
}
+void LocationBarViewMac::SetPreviewEnabledPageAction(
+ ExtensionAction* page_action, bool preview_enabled) {
+ DCHECK(page_action);
+ Browser* browser = BrowserList::GetLastActive();
+ // GetLastActive returns NULL in current unit testing.
+ if (!browser)
+ return;
+ TabContents* contents = browser->GetSelectedTabContents();
+ DCHECK(contents);
+ page_action_views_->RefreshViews();
+
+ LocationBarViewMac::PageActionImageView* page_action_image_view =
+ GetPageActionImageView(page_action);
+ DCHECK(page_action_image_view);
+ if (!page_action_image_view)
+ return;
+
+ page_action_image_view->set_preview_enabled(preview_enabled);
+ page_action_image_view->UpdateVisibility(contents,
+ GURL(WideToUTF8(toolbar_model_->GetText())));
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
+ Source<ExtensionAction>(page_action),
+ Details<TabContents>(contents));
+}
+
+size_t LocationBarViewMac::GetPageActionIndex(ExtensionAction* page_action) {
+ DCHECK(page_action);
+ for (size_t i = 0; i < page_action_views_->Count(); ++i) {
+ if (page_action_views_->ViewAt(i)->page_action() == page_action)
+ return i;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+LocationBarViewMac::PageActionImageView*
+ LocationBarViewMac::GetPageActionImageView(ExtensionAction* page_action) {
+ DCHECK(page_action);
+ for (size_t i = 0; i < page_action_views_->Count(); ++i) {
+ if (page_action_views_->ViewAt(i)->page_action() == page_action)
+ return page_action_views_->ViewAt(i);
+ }
+ NOTREACHED();
+ return NULL;
+}
+
ExtensionAction* LocationBarViewMac::GetPageAction(size_t index) {
if (index < page_action_views_->Count())
return page_action_views_->ViewAt(index)->page_action();
@@ -544,6 +592,19 @@ LocationBarViewMac::PageActionImageView::~PageActionImageView() {
tracker_->StopTrackingImageLoad();
}
+NSSize LocationBarViewMac::PageActionImageView::GetImageSize() {
+ NSImage* image = GetImage();
+ if (preview_enabled_ && !image) {
+ return NSMakeSize(Extension::kPageActionIconMaxSize,
+ Extension::kPageActionIconMaxSize);
+ } else if (image) {
+ return [image size];
+ }
+ // Default value for image size is undefined when preview is not enabled.
+ NOTREACHED();
+ return NSMakeSize(0, 0);
+}
+
// Overridden from LocationBarImageView. Either notify listeners or show a
// popup depending on the Page Action.
bool LocationBarViewMac::PageActionImageView::OnMousePressed(NSRect bounds) {
@@ -603,6 +664,9 @@ void LocationBarViewMac::PageActionImageView::OnImageLoaded(SkBitmap* image,
tracker_ = NULL;
owner_->UpdatePageActions();
+
+ if (preview_enabled_)
+ [owner_->GetAutocompleteTextField() display];
}
void LocationBarViewMac::PageActionImageView::UpdateVisibility(
@@ -781,3 +845,4 @@ void LocationBarViewMac::PageActionViewList::OnMousePressed(NSRect iconFrame,
size_t index) {
ViewAt(index)->OnMousePressed(iconFrame);
}
+
diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h
index 6cc130d..fe9c997 100644
--- a/chrome/browser/cocoa/toolbar_controller.h
+++ b/chrome/browser/cocoa/toolbar_controller.h
@@ -159,6 +159,8 @@ class ToolbarModel;
// Create and add the Browser Action buttons to the toolbar view.
- (void)createBrowserActionButtons;
+// Return the BrowserActionsController for this toolbar.
+- (BrowserActionsController*)browserActionsController;
@end
// A set of private methods used by tests, in the absence of "friends" in ObjC.
@@ -170,7 +172,6 @@ class ToolbarModel;
- (gfx::Rect)locationStackBounds;
// Return a hover button for the current event.
- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent;
-- (BrowserActionsController*)browserActionsController;
@end
#endif // CHROME_BROWSER_COCOA_TOOLBAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm
index ba7075c..59b3c47 100644
--- a/chrome/browser/cocoa/toolbar_controller.mm
+++ b/chrome/browser/cocoa/toolbar_controller.mm
@@ -340,10 +340,6 @@ class PrefObserverBridge : public NotificationObserver {
return nil;
}
-- (BrowserActionsController*)browserActionsController {
- return browserActionsController_.get();
-}
-
- (void)mouseMoved:(NSEvent*)theEvent {
NSButton* targetView = [self hoverButtonForEvent:theEvent];
if (hoveredButton_ != targetView) {
@@ -724,6 +720,10 @@ class PrefObserverBridge : public NotificationObserver {
}
}
+- (BrowserActionsController*)browserActionsController {
+ return browserActionsController_.get();
+}
+
- (NSString*)view:(NSView*)view
stringForToolTip:(NSToolTipTag)tag
point:(NSPoint)point
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index 70347ff..ef410d1 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -35,6 +35,10 @@
#include "chrome/browser/gtk/gtk_theme_provider.h"
#endif
+#if defined(OS_MACOSX)
+#include "chrome/browser/cocoa/extension_installed_bubble_bridge.h"
+#endif
+
namespace {
static std::wstring GetInstallWarning(Extension* extension) {
@@ -196,15 +200,26 @@ void ExtensionInstallUI::OnInstallSuccess(Extension* extension) {
return;
ExtensionInstalledBubble::Show(extension, browser, icon_);
+#elif defined(OS_MACOSX)
+ if (extension->browser_action() ||
+ (extension->page_action() &&
+ !extension->page_action()->default_icon_path().empty())) {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
+ DCHECK(browser);
+ ExtensionInstalledBubbleCocoa::ShowExtensionInstalledBubble(
+ browser->window()->GetNativeHandle(),
+ extension, browser, icon_);
+ } else {
+ // If the extension is of type GENERIC, launch infobar instead of popup
+ // bubble, because we have no guaranteed wrench menu button to point to.
+ ShowGenericExtensionInstalledInfoBar(extension);
+ }
#elif defined(TOOLKIT_GTK)
Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
if (!browser)
return;
-
ExtensionInstalledBubbleGtk::Show(extension, browser, icon_);
-#else
-// TODO(port) crbug.com/26974 (mac)
-#endif
+#endif // TOOLKIT_VIEWS
}
void ExtensionInstallUI::OnInstallFailure(const std::string& error) {
@@ -253,6 +268,26 @@ void ExtensionInstallUI::ShowThemeInfoBar(Extension* new_theme) {
tab_contents->AddInfoBar(new_delegate);
}
+#if defined(OS_MACOSX)
+void ExtensionInstallUI::ShowGenericExtensionInstalledInfoBar(
+ Extension* new_extension) {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
+ if (!browser)
+ return;
+
+ TabContents* tab_contents = browser->GetSelectedTabContents();
+ if (!tab_contents)
+ return;
+
+ std::wstring msg = l10n_util::GetStringF(IDS_EXTENSION_INSTALLED_HEADING,
+ UTF8ToWide(new_extension->name())) +
+ L" " + l10n_util::GetString(IDS_EXTENSION_INSTALLED_MANAGE_INFO_MAC);
+ InfoBarDelegate* delegate = new SimpleAlertInfoBarDelegate(
+ tab_contents, msg, new SkBitmap(icon_));
+ tab_contents->AddInfoBar(delegate);
+}
+#endif
+
InfoBarDelegate* ExtensionInstallUI::GetNewInfoBarDelegate(
Extension* new_theme, TabContents* tab_contents) {
#if defined(TOOLKIT_GTK)
diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h
index dcf8cd9..3e51659 100644
--- a/chrome/browser/extensions/extension_install_ui.h
+++ b/chrome/browser/extensions/extension_install_ui.h
@@ -81,6 +81,12 @@ class ExtensionInstallUI {
// the user a choice to keep it or undo the installation.
void ShowThemeInfoBar(Extension* new_theme);
+#if defined(OS_MACOSX)
+ // When an extension is installed on Mac with neither browser action nor
+ // page action icons, show an infobar instead of a popup bubble.
+ void ShowGenericExtensionInstalledInfoBar(Extension* new_extension);
+#endif
+
// Returns the delegate to control the browser's info bar. This is within its
// own function due to its platform-specific nature.
InfoBarDelegate* GetNewInfoBarDelegate(Extension* new_theme,
diff --git a/chrome/browser/tab_contents/infobar_delegate.h b/chrome/browser/tab_contents/infobar_delegate.h
index 191a9bb..fcaa621 100644
--- a/chrome/browser/tab_contents/infobar_delegate.h
+++ b/chrome/browser/tab_contents/infobar_delegate.h
@@ -44,7 +44,7 @@ class ThemeInstalledInfoBarDelegate;
// AddInfoBar!
class InfoBarDelegate {
public:
- // The type of the infobar. It controls its appearence, such as its background
+ // The type of the infobar. It controls its appearance, such as its background
// color.
enum Type {
INFO_TYPE,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 91da6e8..c3d1ba5 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -458,6 +458,10 @@
'browser/cocoa/event_utils.h',
'browser/cocoa/event_utils.mm',
'browser/cocoa/extension_install_prompt.mm',
+ 'browser/cocoa/extension_installed_bubble_bridge.h',
+ 'browser/cocoa/extension_installed_bubble_bridge.mm',
+ 'browser/cocoa/extension_installed_bubble_controller.h',
+ 'browser/cocoa/extension_installed_bubble_controller.mm',
'browser/cocoa/extension_view_mac.h',
'browser/cocoa/extension_view_mac.mm',
'browser/cocoa/extensions/browser_action_button.h',
@@ -2170,6 +2174,7 @@
'app/nibs/DownloadItem.xib',
'app/nibs/DownloadShelf.xib',
'app/nibs/EditSearchEngine.xib',
+ 'app/nibs/ExtensionInstalledBubble.xib',
'app/nibs/FirstRunDialog.xib',
'app/nibs/FontLanguageSettings.xib',
'app/nibs/HttpAuthLoginSheet.xib',
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index 29edb9e..528709a 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -191,6 +191,7 @@
'app/nibs/DownloadItem.xib',
'app/nibs/DownloadShelf.xib',
'app/nibs/EditSearchEngine.xib',
+ 'app/nibs/ExtensionInstalledBubble.xib',
'app/nibs/FindBar.xib',
'app/nibs/FirstRunDialog.xib',
'app/nibs/FontLanguageSettings.xib',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 1e5823b..c6115d7 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -608,6 +608,7 @@
'browser/cocoa/download_util_mac_unittest.mm',
'browser/cocoa/draggable_button_unittest.mm',
'browser/cocoa/edit_search_engine_cocoa_controller_unittest.mm',
+ 'browser/cocoa/extension_installed_bubble_controller_unittest.mm',
'browser/cocoa/extensions/extension_popup_controller_unittest.mm',
'browser/cocoa/event_utils_unittest.mm',
'browser/cocoa/fast_resize_view_unittest.mm',