diff options
author | mirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-31 21:45:17 +0000 |
---|---|---|
committer | mirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-31 21:45:17 +0000 |
commit | 54bc0925f6430d3fd94fbfc8cabff0a41128701a (patch) | |
tree | 0596552395a069054716171e111bb5c971367290 | |
parent | 007cb731cd1d0af76a0688faa5d1e125c6f57db3 (diff) | |
download | chromium_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
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', |