diff options
author | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-21 23:57:19 +0000 |
---|---|---|
committer | jrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-21 23:57:19 +0000 |
commit | ee01535e43949832b8fb57a74d892390e01d36dd (patch) | |
tree | 630574b28df21ef914369b9a16c0bfdca1b74527 | |
parent | d7aef10706a8e8b5da86d48113136887b3ca97a1 (diff) | |
download | chromium_src-ee01535e43949832b8fb57a74d892390e01d36dd.zip chromium_src-ee01535e43949832b8fb57a74d892390e01d36dd.tar.gz chromium_src-ee01535e43949832b8fb57a74d892390e01d36dd.tar.bz2 |
Implement bookmark editor. No tree display or hierarchy movement, but
name/url editing works. Get to the edotir from a context menu (Edit,
Add Page). Also Implement Open All Bookmarks menu item.
BUG=http://crbug.com/8381, http://crbug.com/17006
TEST=Add some bookmarks.
Right-click on a bookmark and pick Edit.
Test editing the name and URL. Make sure you can't add a bogus URL.
Right-click on a bookmark or the bar and Add Page.
Fill in name and URL fields to add a new bookmark.
Right-click Open All Bookmarks and make sure it hoses your machine.
Review URL: http://codereview.chromium.org/155874
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21241 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/nibs/BookmarkBar.xib | 78 | ||||
-rw-r--r-- | chrome/app/nibs/BookmarkEditor.xib | 624 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.h | 13 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller.mm | 54 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller_unittest.mm | 135 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_editor_controller.h | 54 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_editor_controller.mm | 186 | ||||
-rw-r--r-- | chrome/browser/cocoa/bookmark_editor_controller_unittest.mm | 105 | ||||
-rw-r--r-- | chrome/chrome.gyp | 6 |
9 files changed, 1191 insertions, 64 deletions
diff --git a/chrome/app/nibs/BookmarkBar.xib b/chrome/app/nibs/BookmarkBar.xib index 2002d9b..4abb7d0 100644 --- a/chrome/app/nibs/BookmarkBar.xib +++ b/chrome/app/nibs/BookmarkBar.xib @@ -8,9 +8,9 @@ <string key="IBDocument.HIToolboxVersion">353.00</string> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> - <integer value="1"/> - <integer value="4"/> <integer value="18"/> + <integer value="4"/> + <integer value="1"/> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -301,14 +301,6 @@ <object class="IBActionConnection" key="connection"> <string key="label">commandDispatch:</string> <reference key="source" ref="1003"/> - <reference key="destination" ref="6422781"/> - </object> - <int key="connectionID">32</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">commandDispatch:</string> - <reference key="source" ref="1003"/> <reference key="destination" ref="115646576"/> </object> <int key="connectionID">33</int> @@ -341,14 +333,6 @@ <object class="IBActionConnection" key="connection"> <string key="label">commandDispatch:</string> <reference key="source" ref="1003"/> - <reference key="destination" ref="926809071"/> - </object> - <int key="connectionID">37</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">commandDispatch:</string> - <reference key="source" ref="1003"/> <reference key="destination" ref="90793013"/> </object> <int key="connectionID">38</int> @@ -373,22 +357,6 @@ <object class="IBActionConnection" key="connection"> <string key="label">commandDispatch:</string> <reference key="source" ref="1003"/> - <reference key="destination" ref="182996500"/> - </object> - <int key="connectionID">44</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">commandDispatch:</string> - <reference key="source" ref="1003"/> - <reference key="destination" ref="527115352"/> - </object> - <int key="connectionID">46</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">commandDispatch:</string> - <reference key="source" ref="1003"/> <reference key="destination" ref="595609715"/> </object> <int key="connectionID">47</int> @@ -441,6 +409,38 @@ </object> <int key="connectionID">55</int> </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">editBookmark:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="182996500"/> + </object> + <int key="connectionID">56</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">openAllBookmarks:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="6422781"/> + </object> + <int key="connectionID">57</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">addPage:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="527115352"/> + </object> + <int key="connectionID">58</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">addPage:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="926809071"/> + </object> + <int key="connectionID">59</int> + </object> </object> <object class="IBMutableOrderedSet" key="objectRecords"> <object class="NSArray" key="orderedObjects"> @@ -735,7 +735,7 @@ </object> </object> <nil key="sourceID"/> - <int key="maxID">55</int> + <int key="maxID">59</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> @@ -755,7 +755,10 @@ <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSMutableArray" key="dict.sortedKeys"> <bool key="EncodedWithXMLCoder">YES</bool> + <string>addPage:</string> <string>deleteBookmark:</string> + <string>editBookmark:</string> + <string>openAllBookmarks:</string> <string>openBookmark:</string> <string>openBookmarkInIncognitoWindow:</string> <string>openBookmarkInNewForegroundTab:</string> @@ -768,6 +771,9 @@ <string>id</string> <string>id</string> <string>id</string> + <string>id</string> + <string>id</string> + <string>id</string> </object> </object> <object class="NSMutableDictionary" key="outlets"> @@ -848,7 +854,7 @@ </object> </object> <int key="IBDocument.localizationMode">0</int> - <string key="IBDocument.LastKnownRelativeProjectPath">../../../chrome.xcodeproj</string> + <string key="IBDocument.LastKnownRelativeProjectPath">../../chrome.xcodeproj</string> <int key="IBDocument.defaultPropertyAccessControl">3</int> </data> </archive> diff --git a/chrome/app/nibs/BookmarkEditor.xib b/chrome/app/nibs/BookmarkEditor.xib new file mode 100644 index 0000000..d574a2e --- /dev/null +++ b/chrome/app/nibs/BookmarkEditor.xib @@ -0,0 +1,624 @@ +<?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">9J61</string> + <string key="IBDocument.InterfaceBuilderVersion">677</string> + <string key="IBDocument.AppKitVersion">949.46</string> + <string key="IBDocument.HIToolboxVersion">353.00</string> + <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="2"/> + </object> + <object class="NSArray" key="IBDocument.PluginDependencies"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSCustomObject" id="1001"> + <string key="NSClassName">BookmarkEditorController</string> + </object> + <object class="NSCustomObject" id="1003"> + <string key="NSClassName">FirstResponder</string> + </object> + <object class="NSCustomObject" id="1004"> + <string key="NSClassName">NSApplication</string> + </object> + <object class="NSWindowTemplate" id="1005"> + <int key="NSWindowStyleMask">15</int> + <int key="NSWindowBacking">2</int> + <string key="NSWindowRect">{{196, 240}, {480, 270}}</string> + <int key="NSWTFlags">536870912</int> + <string key="NSWindowTitle">Edit Bookmark</string> + <string key="NSWindowClass">NSWindow</string> + <nil key="NSViewClass"/> + <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> + <string key="NSWindowContentMinSize">{331, 270}</string> + <object class="NSView" key="NSWindowView" id="1006"> + <reference key="NSNextResponder"/> + <int key="NSvFlags">256</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSButton" id="631907363"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{14, 12}, {111, 32}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="732374144"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">New Folder</string> + <object class="NSFont" key="NSSupport" id="899171858"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">1.300000e+01</double> + <int key="NSfFlags">1044</int> + </object> + <reference key="NSControlView" ref="631907363"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">129</int> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + <object class="NSButton" id="983581711"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">289</int> + <string key="NSFrame">{{370, 12}, {96, 32}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="137649770"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">OK</string> + <reference key="NSSupport" ref="899171858"/> + <reference key="NSControlView" ref="983581711"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">129</int> + <string key="NSAlternateContents"/> + <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + <object class="NSButton" id="110527617"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">289</int> + <string key="NSFrame">{{274, 12}, {96, 32}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="820689210"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Cancel</string> + <reference key="NSSupport" ref="899171858"/> + <reference key="NSControlView" ref="110527617"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">268435585</int> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent">.</string> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + <object class="NSTextField" id="1036501322"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">268</int> + <string key="NSFrame">{{17, 230}, {45, 17}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="52444064"> + <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents">Name:</string> + <reference key="NSSupport" ref="899171858"/> + <reference key="NSControlView" ref="1036501322"/> + <object class="NSColor" key="NSBackgroundColor" id="519536938"> + <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="728676191"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlTextColor</string> + <object class="NSColor" key="NSColor" id="528526553"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + </object> + </object> + </object> + </object> + <object class="NSTextField" id="209927002"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">268</int> + <string key="NSFrame">{{17, 205}, {38, 17}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="268808428"> + <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents">URL:</string> + <reference key="NSSupport" ref="899171858"/> + <reference key="NSControlView" ref="209927002"/> + <reference key="NSBackgroundColor" ref="519536938"/> + <reference key="NSTextColor" ref="728676191"/> + </object> + </object> + <object class="NSTextField" id="921757931"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">266</int> + <string key="NSFrame">{{74, 228}, {386, 22}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="1025899850"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="899171858"/> + <reference key="NSControlView" ref="921757931"/> + <bool key="NSDrawsBackground">YES</bool> + <object class="NSColor" key="NSBackgroundColor" id="31051313"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">textBackgroundColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MQA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor" id="90031784"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">textColor</string> + <reference key="NSColor" ref="528526553"/> + </object> + </object> + </object> + <object class="NSTextField" id="812603726"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">266</int> + <string key="NSFrame">{{74, 203}, {386, 22}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="991096593"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="899171858"/> + <reference key="NSControlView" ref="812603726"/> + <bool key="NSDrawsBackground">YES</bool> + <reference key="NSBackgroundColor" ref="31051313"/> + <reference key="NSTextColor" ref="90031784"/> + </object> + </object> + <object class="NSBrowser" id="723395462"> + <reference key="NSNextResponder" ref="1006"/> + <int key="NSvFlags">268</int> + <string key="NSFrame">{{20, 60}, {440, 143}}</string> + <reference key="NSSuperview" ref="1006"/> + <bool key="NSEnabled">YES</bool> + <object class="NSBrowserCell" key="NSCellPrototype"> + <int key="NSCellFlags">67239488</int> + <int key="NSCellFlags2">2048</int> + <string key="NSContents"> </string> + <object class="NSFont" key="NSSupport"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">1.200000e+01</double> + <int key="NSfFlags">16</int> + </object> + </object> + <string key="NSPathSeparator">/</string> + <int key="NSMinColumnWidth">100</int> + <int key="NSNumberOfVisibleColumns">3</int> + <int key="NSColumnResizingType">1</int> + <double key="NSPreferedColumnWidth">1.000000e+02</double> + <bool key="NSAllowsTypeSelect">YES</bool> + <int key="NSBrFlags">469843968</int> + </object> + </object> + <string key="NSFrameSize">{480, 270}</string> + <reference key="NSSuperview"/> + </object> + <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string> + <string key="NSMinSize">{331, 292}</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="IBActionConnection" key="connection"> + <string key="label">newFolder:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="631907363"/> + </object> + <int key="connectionID">21</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">cancel:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="110527617"/> + </object> + <int key="connectionID">22</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">ok:</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="983581711"/> + </object> + <int key="connectionID">23</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">nameField_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="921757931"/> + </object> + <int key="connectionID">24</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">urlField_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="812603726"/> + </object> + <int key="connectionID">25</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">browser_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="723395462"/> + </object> + <int key="connectionID">27</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">window</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="1005"/> + </object> + <int key="connectionID">28</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="1005"/> + <reference key="destination" ref="1001"/> + </object> + <int key="connectionID">29</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">newFolderButton_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="631907363"/> + </object> + <int key="connectionID">30</int> + </object> + </object> + <object class="IBMutableOrderedSet" key="objectRecords"> + <object class="NSArray" key="orderedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBObjectRecord"> + <int key="objectID">0</int> + <object class="NSArray" key="object" id="1002"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <reference key="children" ref="1000"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="1001"/> + <reference key="parent" ref="1002"/> + <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="1003"/> + <reference key="parent" ref="1002"/> + <string key="objectName">First Responder</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-3</int> + <reference key="object" ref="1004"/> + <reference key="parent" ref="1002"/> + <string key="objectName">Application</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">1</int> + <reference key="object" ref="1005"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="1006"/> + </object> + <reference key="parent" ref="1002"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">2</int> + <reference key="object" ref="1006"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="631907363"/> + <reference ref="110527617"/> + <reference ref="921757931"/> + <reference ref="1036501322"/> + <reference ref="812603726"/> + <reference ref="209927002"/> + <reference ref="723395462"/> + <reference ref="983581711"/> + </object> + <reference key="parent" ref="1005"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">3</int> + <reference key="object" ref="631907363"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="732374144"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">4</int> + <reference key="object" ref="732374144"/> + <reference key="parent" ref="631907363"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">5</int> + <reference key="object" ref="983581711"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="137649770"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">6</int> + <reference key="object" ref="137649770"/> + <reference key="parent" ref="983581711"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">7</int> + <reference key="object" ref="110527617"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="820689210"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">8</int> + <reference key="object" ref="820689210"/> + <reference key="parent" ref="110527617"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">9</int> + <reference key="object" ref="1036501322"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="52444064"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">10</int> + <reference key="object" ref="52444064"/> + <reference key="parent" ref="1036501322"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">11</int> + <reference key="object" ref="209927002"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="268808428"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">12</int> + <reference key="object" ref="268808428"/> + <reference key="parent" ref="209927002"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">13</int> + <reference key="object" ref="921757931"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="1025899850"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">14</int> + <reference key="object" ref="1025899850"/> + <reference key="parent" ref="921757931"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">15</int> + <reference key="object" ref="812603726"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="991096593"/> + </object> + <reference key="parent" ref="1006"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">16</int> + <reference key="object" ref="991096593"/> + <reference key="parent" ref="812603726"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">26</int> + <reference key="object" ref="723395462"/> + <reference key="parent" ref="1006"/> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="flattenedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMutableArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>-1.IBPluginDependency</string> + <string>-2.IBPluginDependency</string> + <string>-3.IBPluginDependency</string> + <string>1.IBEditorWindowLastContentRect</string> + <string>1.IBPluginDependency</string> + <string>1.IBWindowTemplateEditedContentRect</string> + <string>1.NSWindowTemplate.visibleAtLaunch</string> + <string>1.WindowOrigin</string> + <string>1.editorWindowContentRectSynchronizationRect</string> + <string>1.windowTemplate.hasMaxSize</string> + <string>1.windowTemplate.hasMinSize</string> + <string>1.windowTemplate.maxSize</string> + <string>1.windowTemplate.minSize</string> + <string>10.IBPluginDependency</string> + <string>11.IBPluginDependency</string> + <string>12.IBPluginDependency</string> + <string>13.IBPluginDependency</string> + <string>14.IBPluginDependency</string> + <string>15.IBPluginDependency</string> + <string>16.IBPluginDependency</string> + <string>2.IBPluginDependency</string> + <string>26.IBPluginDependency</string> + <string>3.IBPluginDependency</string> + <string>4.IBPluginDependency</string> + <string>5.IBPluginDependency</string> + <string>6.IBPluginDependency</string> + <string>7.IBPluginDependency</string> + <string>8.IBPluginDependency</string> + <string>9.IBPluginDependency</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{609, 978}, {480, 270}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{609, 978}, {480, 270}}</string> + <boolean value="NO" id="6"/> + <string>{196, 240}</string> + <string>{{357, 418}, {480, 270}}</string> + <reference ref="6"/> + <boolean value="YES"/> + <string>{331, 270}</string> + <string>{331, 270}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + </object> + <object class="NSMutableDictionary" key="unlocalizedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="activeLocalization"/> + <object class="NSMutableDictionary" key="localizations"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="sourceID"/> + <int key="maxID">30</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <object class="NSMutableArray" key="referencedPartialClassDescriptions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">BookmarkEditorController</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>cancel:</string> + <string>newFolder:</string> + <string>ok:</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="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMutableArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>browser_</string> + <string>nameField_</string> + <string>newFolderButton_</string> + <string>urlField_</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>NSBrowser</string> + <string>NSTextField</string> + <string>NSButton</string> + <string>NSTextField</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/cocoa/bookmark_editor_controller.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> + </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/bookmark_bar_controller.h b/chrome/browser/cocoa/bookmark_bar_controller.h index 662da61..6e57bfa 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.h +++ b/chrome/browser/cocoa/bookmark_bar_controller.h @@ -29,9 +29,9 @@ class PrefService; // and hiding based on the preference in the given profile. @interface BookmarkBarController : NSViewController { @private + Profile* profile_; // weak BookmarkModel* bookmarkModel_; // weak; part of the profile owned by the // top-level Browser object. - PrefService* preferences_; // (ditto) // Currently these two are always the same when not in fullscreen // mode, but they mean slightly different things. @@ -83,13 +83,20 @@ class PrefService; // if needed. For fullscreen mode. - (void)setBookmarkBarEnabled:(BOOL)enabled; -// Actions for opening bookmarks. From a button, ... +// Actions for manipulating bookmarks. +// From a button, ... - (IBAction)openBookmark:(id)sender; -// ... or from a context menu over the button. +// From a context menu over the button, ... - (IBAction)openBookmarkInNewForegroundTab:(id)sender; - (IBAction)openBookmarkInNewWindow:(id)sender; - (IBAction)openBookmarkInIncognitoWindow:(id)sender; +- (IBAction)editBookmark:(id)sender; - (IBAction)deleteBookmark:(id)sender; +// From a context menu over the bar, ... +- (IBAction)openAllBookmarks:(id)sender; +// Or from a context menu over either the bar or a button. +- (IBAction)addPage:(id)sender; + @end diff --git a/chrome/browser/cocoa/bookmark_bar_controller.mm b/chrome/browser/cocoa/bookmark_bar_controller.mm index d4af000..65a8135 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller.mm @@ -4,6 +4,7 @@ #include "base/mac_util.h" #include "base/sys_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_editor.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" @@ -11,6 +12,7 @@ #import "chrome/browser/cocoa/bookmark_bar_controller.h" #import "chrome/browser/cocoa/bookmark_bar_view.h" #import "chrome/browser/cocoa/bookmark_button_cell.h" +#import "chrome/browser/cocoa/bookmark_editor_controller.h" #include "chrome/browser/profile.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" @@ -48,8 +50,8 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; delegate:(id<BookmarkURLOpener>)delegate { if ((self = [super initWithNibName:@"BookmarkBar" bundle:mac_util::MainAppBundle()])) { + profile_ = profile; bookmarkModel_ = profile->GetBookmarkModel(); - preferences_ = profile->GetPrefs(); parentView_ = parentView; webContentView_ = webContentView; infoBarsView_ = infoBarsView; @@ -72,7 +74,7 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; NSViewMinYMargin)]; // Be sure to enable the bar before trying to show it... barIsEnabled_ = YES; - if (preferences_->GetBoolean(prefs::kShowBookmarkBar)) + if (profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar)) [self showBookmarkBar:YES immediately:YES]; // Don't pass ourself along (as 'self') until our init is completely @@ -181,7 +183,7 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; if (enabled) { // Enabling the bar; set enabled then show if needed. barIsEnabled_ = YES; - if (preferences_->GetBoolean(prefs::kShowBookmarkBar)) + if (profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar)) [self showBookmarkBar:YES immediately:YES]; } else { // Disabling the bar; hide if visible. @@ -232,12 +234,58 @@ const CGFloat kBookmarkHorizontalPadding = 1.0; [delegate_ openBookmarkURL:node->GetURL() disposition:OFF_THE_RECORD]; } +- (IBAction)editBookmark:(id)sender { + BookmarkNode* node = [self nodeFromMenuItem:sender]; + // There is no real need to jump to a platform-common routine at + // this point (which just jumps back to objc) other than consistency + // across platforms. + // + // TODO(jrg): identify when we NO_TREE. I can see it in the code + // for the other platforms but can't find a way to trigger it in the + // UI. + BookmarkEditor::Show([[[self view] window] contentView], + profile_, + node->GetParent(), + node, + BookmarkEditor::SHOW_TREE, + nil); +} + - (IBAction)deleteBookmark:(id)sender { BookmarkNode* node = [self nodeFromMenuItem:sender]; bookmarkModel_->Remove(node->GetParent(), node->GetParent()->IndexOfChild(node)); } +- (void)openBookmarkNodesRecursive:(BookmarkNode*)node { + for (int i = 0; i < node->GetChildCount(); i++) { + BookmarkNode* child = node->GetChild(i); + if (child->is_url()) + [delegate_ openBookmarkURL:child->GetURL() + disposition:NEW_BACKGROUND_TAB]; + else + [self openBookmarkNodesRecursive:child]; + } +} + +- (IBAction)openAllBookmarks:(id)sender { + // TODO(jrg): + // Is there an easier way to get a non-const root node for the bookmark bar? + // I can't iterate over them unless it's non-const. + + BookmarkNode* node = (BookmarkNode*)bookmarkModel_->GetBookmarkBarNode(); + [self openBookmarkNodesRecursive:node]; +} + +- (IBAction)addPage:(id)sender { + BookmarkEditor::Show([[[self view] window] contentView], + profile_, + bookmarkModel_->GetBookmarkBarNode(), + nil, + BookmarkEditor::SHOW_TREE, + nil); +} + // Delete all bookmarks from the bookmark bar. - (void)clearBookmarkBar { [buttons_ makeObjectsPerformSelector:@selector(removeFromSuperview)]; diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm index e1dbdbc..095e3bd 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm @@ -4,6 +4,7 @@ #import <Cocoa/Cocoa.h> +#include "base/basictypes.h" #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/bookmark_bar_controller.h" #include "chrome/browser/cocoa/browser_test_helper.h" @@ -13,16 +14,20 @@ // Pretend BookmarkURLOpener delegate to keep track of requests @interface BookmarkURLOpenerPong : NSObject<BookmarkURLOpener> { @public - GURL url_; - WindowOpenDisposition disposition_; + std::vector<GURL> urls_; + std::vector<WindowOpenDisposition> dispositions_; } @end @implementation BookmarkURLOpenerPong - (void)openBookmarkURL:(const GURL&)url disposition:(WindowOpenDisposition)disposition { - url_ = url; - disposition_ = disposition; + urls_.push_back(url); + dispositions_.push_back(disposition); +} +- (void)clear { + urls_.clear(); + dispositions_.clear(); } @end @@ -83,14 +88,42 @@ class BookmarkBarControllerTest : public testing::Test { // make sure it's open so certain things aren't no-ops [bar_ toggleBookmarkBar]; + + // Create a menu/item to act like a sender + menu_.reset([[NSMenu alloc] initWithTitle:@"I_dont_care"]); + menu_item_.reset([[NSMenuItem alloc] + initWithTitle:@"still_dont_care" + action:NULL + keyEquivalent:@""]); + cell_.reset([[NSButtonCell alloc] init]); + [menu_item_ setMenu:menu_.get()]; + [menu_ setDelegate:cell_.get()]; + } + + // Return a menu item that points to the right URL. + NSMenuItem* ItemForBookmarkBarMenu(GURL& gurl) { + node_.reset(new BookmarkNode(gurl)); + [cell_ setRepresentedObject:[NSValue valueWithPointer:node_.get()]]; + return menu_item_; } + // Does NOT take ownership of node. + NSMenuItem* ItemForBookmarkBarMenu(const BookmarkNode* node) { + [cell_ setRepresentedObject:[NSValue valueWithPointer:node]]; + return menu_item_; + } + + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... scoped_nsobject<NSView> content_area_; scoped_nsobject<NSView> infobar_view_; scoped_nsobject<NSView> parent_view_; BrowserTestHelper helper_; scoped_nsobject<BookmarkBarController> bar_; + scoped_nsobject<NSMenu> menu_; + scoped_nsobject<NSMenuItem> menu_item_; + scoped_nsobject<NSButtonCell> cell_; + scoped_ptr<BookmarkNode> node_; }; TEST_F(BookmarkBarControllerTest, ShowHide) { @@ -139,8 +172,8 @@ TEST_F(BookmarkBarControllerTest, OpenBookmark) { [cell setRepresentedObject:[NSValue valueWithPointer:node.get()]]; [bar_ openBookmark:button]; - EXPECT_EQ(pong.get()->url_, node->GetURL()); - EXPECT_EQ(pong.get()->disposition_, CURRENT_TAB); + EXPECT_EQ(pong.get()->urls_[0], node->GetURL()); + EXPECT_EQ(pong.get()->dispositions_[0], CURRENT_TAB); [bar_ setDelegate:nil]; } @@ -152,15 +185,6 @@ TEST_F(BookmarkBarControllerTest, OpenBookmarkFromMenus) { init]); [bar_ setDelegate:pong.get()]; - scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"I_dont_care"]); - scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc] - initWithTitle:@"still_dont_care" - action:NULL - keyEquivalent:@""]); - scoped_nsobject<NSButtonCell> cell([[NSButtonCell alloc] init]); - [item setMenu:menu.get()]; - [menu setDelegate:cell]; - const char* urls[] = { "http://walla.walla.ding.dong.com", "http://i_dont_know.com", "http://cee.enn.enn.dot.com" }; @@ -173,13 +197,14 @@ TEST_F(BookmarkBarControllerTest, OpenBookmarkFromMenus) { for (unsigned int i = 0; i < sizeof(dispositions)/sizeof(dispositions[0]); i++) { - scoped_ptr<BookmarkNode> node(new BookmarkNode(GURL(urls[i]))); - [cell setRepresentedObject:[NSValue valueWithPointer:node.get()]]; - [bar_ performSelector:selectors[i] withObject:item.get()]; - EXPECT_EQ(pong.get()->url_, node->GetURL()); - EXPECT_EQ(pong.get()->disposition_, dispositions[i]); - [cell setRepresentedObject:nil]; + GURL gurl(urls[i]); + [bar_ performSelector:selectors[i] + withObject:ItemForBookmarkBarMenu(gurl)]; + EXPECT_EQ(pong.get()->urls_[0], gurl); + EXPECT_EQ(pong.get()->dispositions_[0], dispositions[i]); + [pong clear]; } + [bar_ setDelegate:nil]; } TEST_F(BookmarkBarControllerTest, TestAddRemoveAndClear) { @@ -278,6 +303,69 @@ TEST_F(BookmarkBarControllerTest, CheckForGrowth) { EXPECT_GE(frame_2.origin.x, frame_1.origin.x + frame_1.size.width); } +TEST_F(BookmarkBarControllerTest, DeleteBookmark) { + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + + const char* urls[] = { "https://secret.url.com", + "http://super.duper.web.site.for.doodz.gov", + "http://www.foo-bar-baz.com/" }; + const BookmarkNode* parent = model->GetBookmarkBarNode(); + for (unsigned int i = 0; i < arraysize(urls); i++) { + model->AddURL(parent, parent->GetChildCount(), + L"title", GURL(urls[i])); + } + EXPECT_EQ(3, parent->GetChildCount()); + const BookmarkNode* middle_node = parent->GetChild(1); + + NSMenuItem* item = ItemForBookmarkBarMenu(middle_node); + [bar_ deleteBookmark:item]; + EXPECT_EQ(2, parent->GetChildCount()); + EXPECT_EQ(parent->GetChild(0)->GetURL(), GURL(urls[0])); + // node 2 moved into spot 1 + EXPECT_EQ(parent->GetChild(1)->GetURL(), GURL(urls[2])); +} + +TEST_F(BookmarkBarControllerTest, OpenAllBookmarks) { + scoped_nsobject<BookmarkURLOpenerPong> pong([[BookmarkURLOpenerPong alloc] + init]); + [bar_ setDelegate:pong.get()]; + + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + const BookmarkNode* parent = model->GetBookmarkBarNode(); + // { one, { two-one, two-two }, three } + model->AddURL(parent, parent->GetChildCount(), + L"title", GURL("http://one.com")); + const BookmarkNode* folder = model->AddGroup(parent, + parent->GetChildCount(), + L"group"); + model->AddURL(folder, folder->GetChildCount(), + L"title", GURL("http://two-one.com")); + model->AddURL(folder, folder->GetChildCount(), + L"title", GURL("http://two-two.com")); + model->AddURL(parent, parent->GetChildCount(), + L"title", GURL("https://three.com")); + [bar_ openAllBookmarks:nil]; + + EXPECT_EQ(pong.get()->urls_.size(), 4U); + EXPECT_EQ(pong.get()->dispositions_.size(), 4U); + + // I can't use EXPECT_EQ() here since the macro can't expand + // properly (no way to print the value of an iterator). + std::vector<GURL>::iterator i; + std::vector<GURL>::iterator begin = pong.get()->urls_.begin(); + std::vector<GURL>::iterator end = pong.get()->urls_.end(); + i = find(begin, end, GURL("http://two-one.com")); + EXPECT_FALSE(i == end); + i = find(begin, end, GURL("https://three.com")); + EXPECT_FALSE(i == end); + i = find(begin, end, GURL("https://will-not-be-found.com")); + EXPECT_TRUE(i == end); + + EXPECT_EQ(pong.get()->dispositions_[3], NEW_BACKGROUND_TAB); + + [bar_ setDelegate:nil]; +} + // TODO(jrg): write a test to confirm that nodeFavIconLoaded calls // checkForBookmarkButtonGrowth:. @@ -300,4 +388,9 @@ TEST_F(BookmarkBarControllerTest, Display) { [[bar_ view] display]; } +// Cannot test these methods since they simply call a single static +// method, BookmarkEditor::Show(), which is impossible to mock. +// editBookmark:, addPage: + + } // namespace diff --git a/chrome/browser/cocoa/bookmark_editor_controller.h b/chrome/browser/cocoa/bookmark_editor_controller.h new file mode 100644 index 0000000..e297ea3 --- /dev/null +++ b/chrome/browser/cocoa/bookmark_editor_controller.h @@ -0,0 +1,54 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_CONTROLLER_H_ +#define CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_CONTROLLER_H_ + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_ptr.h" +#include "base/scoped_nsobject.h" +#include "chrome/browser/bookmarks/bookmark_editor.h" + +// A controller for the bookmark editor, opened with Edit... from the +// context menu of a bookmark button. +@interface BookmarkEditorController : NSWindowController { + @private + IBOutlet NSTextField* nameField_; + IBOutlet NSTextField* urlField_; + IBOutlet NSBrowser* browser_; + IBOutlet NSButton* newFolderButton_; + + NSWindow* parentWindow_; + Profile* profile_; // weak + const BookmarkNode* parentNode_; // weak; owned by the model + const BookmarkNode* node_; // weak; owned by the model + BookmarkEditor::Configuration configuration_; + scoped_ptr<BookmarkEditor::Handler> handler_; // we take ownership + + scoped_nsobject<NSString> initialName_; + scoped_nsobject<NSString> initialUrl_; +} + +- (id)initWithParentWindow:(NSWindow*)parentWindow + profile:(Profile*)profile + parent:(const BookmarkNode*)parent + node:(const BookmarkNode*)node + configuration:(BookmarkEditor::Configuration)configuration + handler:(BookmarkEditor::Handler*)handler; + +// Actions for the buttons at the bottom of the window. +- (IBAction)newFolder:(id)sender; +- (IBAction)cancel:(id)sender; +- (IBAction)ok:(id)sender; +@end + +@interface BookmarkEditorController(TestingAPI) +@property (assign) NSString* displayName; +@property (assign) NSString* displayURL; +@end + + +#endif /* CHROME_BROWSER_COCOA_BOOKMARK_EDITOR_CONTROLLER_H_ */ + diff --git a/chrome/browser/cocoa/bookmark_editor_controller.mm b/chrome/browser/cocoa/bookmark_editor_controller.mm new file mode 100644 index 0000000..704c56e --- /dev/null +++ b/chrome/browser/cocoa/bookmark_editor_controller.mm @@ -0,0 +1,186 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "base/mac_util.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_editor.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/profile.h" +#import "chrome/browser/cocoa/bookmark_editor_controller.h" + +@interface BookmarkEditorController(Private) +// Run the bookmark editor as a modal sheet. Does not block. +- (void)runModal; +@end + +// static; implemented for each platform. +void BookmarkEditor::Show(gfx::NativeView parent_hwnd, + Profile* profile, + const BookmarkNode* parent, + const BookmarkNode* node, + Configuration configuration, + Handler* handler) { + NSWindow* window = [parent_hwnd window]; + BookmarkEditorController* controller = [[BookmarkEditorController alloc] + initWithParentWindow:window + profile:profile + parent:parent + node:node + configuration:configuration + handler:handler]; + [controller runModal]; +} + + +@implementation BookmarkEditorController + +- (id)initWithParentWindow:(NSWindow*)parentWindow + profile:(Profile*)profile + parent:(const BookmarkNode*)parent + node:(const BookmarkNode*)node + configuration:(BookmarkEditor::Configuration)configuration + handler:(BookmarkEditor::Handler*)handler { + NSString* nibpath = [mac_util::MainAppBundle() + pathForResource:@"BookmarkEditor" + ofType:@"nib"]; + if ((self = [super initWithWindowNibPath:nibpath owner:self])) { + parentWindow_ = parentWindow; + profile_ = profile; + parentNode_ = parent; + // "Add Page..." has no "node" so this may be NULL. + node_ = node; + configuration_ = configuration; + handler_.reset(handler); + } + return self; +} + +- (void)awakeFromNib { + // Set text fields to match our bookmark. If the node is NULL we + // arrived here from an "Add Page..." item in a context menu. + if (node_) { + initialName_.reset([base::SysWideToNSString(node_->GetTitle()) retain]); + std::string url_string = node_->GetURL().possibly_invalid_spec(); + initialUrl_.reset([[NSString stringWithUTF8String:url_string.c_str()] + retain]); + } else { + initialName_.reset([@"" retain]); + initialUrl_.reset([@"" retain]); + } + [nameField_ setStringValue:initialName_]; + [urlField_ setStringValue:initialUrl_]; + + if (configuration_ == BookmarkEditor::SHOW_TREE) { + // build the tree et al + NOTIMPLEMENTED(); + } else { + // Remember the NSBrowser's height; we will shrink our frame by that + // much. + NSRect frame = [[self window] frame]; + CGFloat browserHeight = [browser_ frame].size.height; + frame.size.height -= browserHeight; + frame.origin.y += browserHeight; + // Remove the NSBrowser and "new folder" button. + [browser_ removeFromSuperview]; + [newFolderButton_ removeFromSuperview]; + // Finally, commit the size change. + [[self window] setFrame:frame display:YES]; + } +} + +/* TODO(jrg): +// Implementing this informal protocol allows us to open the sheet +// somewhere other than at the top of the window. NOTE: this means +// that I, the controller, am also the window's delegate. +- (NSRect)window:(NSWindow*)window willPositionSheet:(NSWindow*)sheet + usingRect:(NSRect)rect { + // adjust rect.origin.y to be the bottom of the toolbar + return rect; +} +*/ + +// TODO(jrg): consider NSModalSession. +- (void)runModal { + [NSApp beginSheet:[self window] + modalForWindow:parentWindow_ + modalDelegate:self + didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) + contextInfo:nil]; +} + +// TODO(jrg) +- (IBAction)newFolder:(id)sender { + NOTIMPLEMENTED(); +} + +- (IBAction)cancel:(id)sender { + [NSApp endSheet:[self window]]; +} + +// TODO(jrg): Once the tree is available edits may be more extensive +// than just name/url. +- (IBAction)ok:(id)sender { + NSString *name = [nameField_ stringValue]; + NSString *url = [urlField_ stringValue]; + + if ((![name isEqual:initialName_]) || + (![url isEqual:initialUrl_])) { + std::wstring newTitle = base::SysNSStringToWide(name); + GURL newURL = GURL([url UTF8String]); + if (!newURL.is_valid()) { + // Mimic observed friendliness from Windows + newURL = GURL([[NSString stringWithFormat:@"http://%@", url] UTF8String]); + } + if (!newURL.is_valid()) { + // Silently ignoring a bad URL is unfriendly. + newURL = GURL(); + } + int index = 0; + BookmarkModel* model = profile_->GetBookmarkModel(); + if (node_) { + index = parentNode_->IndexOfChild(node_); + model->Remove(parentNode_, index); + } else { + index = parentNode_->GetChildCount(); + } + const BookmarkNode* node = model->AddURL(parentNode_, index, + newTitle, newURL); + // Honor handler semantics: callback on node creation + if (handler_.get()) + handler_->NodeCreated(node); + } + + [NSApp endSheet:[self window]]; +} + +- (void)didEndSheet:(NSWindow*)sheet + returnCode:(int)returnCode + contextInfo:(void*)contextInfo { + [[self window] orderOut:self]; + + // BookmarkEditor::Show() will create us then run away. Unusually + // for a controller, we are responsible for deallocating ourself. + [self autorelease]; +} + + +- (NSString*)displayName { + return [nameField_ stringValue]; +} + +- (NSString*)displayURL { + return [urlField_ stringValue]; +} + +- (void)setDisplayName:(NSString*)name { + [nameField_ setStringValue:name]; +} + +- (void)setDisplayURL:(NSString*)name { + [urlField_ setStringValue:name]; +} + +@end // BookmarkEditorController + diff --git a/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm b/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm new file mode 100644 index 0000000..c6bfa83 --- /dev/null +++ b/chrome/browser/cocoa/bookmark_editor_controller_unittest.mm @@ -0,0 +1,105 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/bookmark_editor_controller.h" +#include "chrome/browser/cocoa/browser_test_helper.h" +#import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +class BookmarkEditorControllerTest : public testing::Test { + public: + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... + BrowserTestHelper helper_; + scoped_nsobject<BookmarkEditorController> bar_; +}; + +// Lots TODO here. + +TEST_F(BookmarkEditorControllerTest, NoNodeNoTree) { + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + const BookmarkNode* parent = model->GetBookmarkBarNode(); + const BookmarkNode* node = NULL; + + scoped_nsobject<BookmarkEditorController> + controller([[BookmarkEditorController alloc] + initWithParentWindow:cocoa_helper_.window() + profile:helper_.profile() + parent:parent + node:node + configuration:BookmarkEditor::NO_TREE + handler:nil]); + + EXPECT_NE((NSWindow*)nil, [controller window]); // Forces a nib load + EXPECT_EQ(@"", [controller displayName]); + EXPECT_EQ(@"", [controller displayURL]); +} + +TEST_F(BookmarkEditorControllerTest, YesNodeShowTree) { + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + const BookmarkNode* parent = model->GetBookmarkBarNode(); + const char* url_name = "http://www.zim-bop-a-dee.com/"; + const BookmarkNode* node = model->AddURL(parent, 0, L"ooh title", + GURL(url_name)); + + scoped_nsobject<BookmarkEditorController> + controller([[BookmarkEditorController alloc] + initWithParentWindow:cocoa_helper_.window() + profile:helper_.profile() + parent:parent + node:node + configuration:BookmarkEditor::SHOW_TREE + handler:nil]); + + EXPECT_NE((NSWindow*)nil, [controller window]); // Forces a nib load + EXPECT_TRUE([@"ooh title" isEqual:[controller displayName]]); + EXPECT_TRUE([[NSString stringWithCString:url_name] + isEqual:[controller displayURL]]); +} + +TEST_F(BookmarkEditorControllerTest, UserEditsStuff) { + BookmarkModel* model = helper_.profile()->GetBookmarkModel(); + const BookmarkNode* parent = model->GetBookmarkBarNode(); + const char* url_name = "http://www.zim-bop-a-dee.com/"; + const BookmarkNode* node = model->AddURL(parent, 0, L"ooh title", + GURL(url_name)); + + scoped_nsobject<BookmarkEditorController> + controller([[BookmarkEditorController alloc] + initWithParentWindow:cocoa_helper_.window() + profile:helper_.profile() + parent:parent + node:node + configuration:BookmarkEditor::NO_TREE + handler:nil]); + + EXPECT_NE((NSWindow*)nil, [controller window]); // Forces a nib load + + // No change. + [controller ok:nil]; + const BookmarkNode* child = parent->GetChild(0); + EXPECT_EQ(child->GetTitle(), L"ooh title"); + EXPECT_EQ(child->GetURL(), GURL(url_name)); + + // Change just the title. + [controller setDisplayName:@"whamma jamma bamma"]; + [controller ok:nil]; + child = parent->GetChild(0); + EXPECT_EQ(child->GetTitle(), L"whamma jamma bamma"); + EXPECT_EQ(child->GetURL(), GURL(url_name)); + + // Change just the URL + [controller setDisplayURL:@"http://yellow-sneakers.com/"]; + [controller ok:nil]; + child = parent->GetChild(0); + EXPECT_EQ(child->GetTitle(), L"whamma jamma bamma"); + EXPECT_EQ(child->GetURL(), GURL("http://yellow-sneakers.com/")); +} + + + + + diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 8c20b27..04df059 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -51,7 +51,7 @@ '../views/controls/table/table_view_unittest.cc', '../views/focus/focus_manager_unittest.cc', '../views/grid_layout_unittest.cc', - ] + ] }, 'includes': [ '../build/common.gypi', @@ -758,6 +758,8 @@ 'browser/cocoa/bookmark_bar_view.mm', 'browser/cocoa/bookmark_button_cell.h', 'browser/cocoa/bookmark_button_cell.mm', + 'browser/cocoa/bookmark_editor_controller.h', + 'browser/cocoa/bookmark_editor_controller.mm', 'browser/cocoa/bookmark_menu_bridge.h', 'browser/cocoa/bookmark_menu_bridge.mm', 'browser/cocoa/bookmark_menu_cocoa_controller.h', @@ -2608,6 +2610,7 @@ # them. 'app/nibs/About.xib', 'app/nibs/BookmarkBar.xib', + 'app/nibs/BookmarkEditor.xib', 'app/nibs/BrowserWindow.xib', 'app/nibs/ClearBrowsingData.xib', 'app/nibs/DownloadItem.xib', @@ -3662,6 +3665,7 @@ 'browser/cocoa/bookmark_bar_controller_unittest.mm', 'browser/cocoa/bookmark_bar_view_unittest.mm', 'browser/cocoa/bookmark_button_cell_unittest.mm', + 'browser/cocoa/bookmark_editor_controller_unittest.mm', 'browser/cocoa/bookmark_menu_bridge_unittest.mm', 'browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm', 'browser/cocoa/browser_window_cocoa_unittest.mm', |