summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-05 19:46:04 +0000
committersnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-05 19:46:04 +0000
commit2f7b27eec08656852564942e09af296a76e6dc1f (patch)
treea6df8de35ccb816c487cffb88959c8f4d71865a5
parentcdaea9737d39a207240be700f3436e2a2929424e (diff)
downloadchromium_src-2f7b27eec08656852564942e09af296a76e6dc1f.zip
chromium_src-2f7b27eec08656852564942e09af296a76e6dc1f.tar.gz
chromium_src-2f7b27eec08656852564942e09af296a76e6dc1f.tar.bz2
Native Cocoa bookmark manager, part 1
Most features are implemented, but Recents, Search and Undo are still missing. MainMenu.xib: Just added "Bookmark Manager" menu item at top of "Bookmarks" menu. BookmarkManager.xib: New file, containing Bookmark Manager panel, owned by BookmarkManagerController class. BUG=13149 TEST=New unit tests for each new class. Review URL: http://codereview.chromium.org/501073 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35546 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/app/nibs/BookmarkManager.xib1535
-rw-r--r--chrome/app/nibs/MainMenu.xib236
-rw-r--r--chrome/browser/browser.cc2
-rw-r--r--chrome/browser/cocoa/bookmark_groups_controller.h52
-rw-r--r--chrome/browser/cocoa/bookmark_groups_controller.mm165
-rw-r--r--chrome/browser/cocoa/bookmark_groups_controller_unittest.mm79
-rw-r--r--chrome/browser/cocoa/bookmark_manager_controller.h63
-rw-r--r--chrome/browser/cocoa/bookmark_manager_controller.mm261
-rw-r--r--chrome/browser/cocoa/bookmark_manager_controller_unittest.mm73
-rw-r--r--chrome/browser/cocoa/bookmark_tree_controller.h68
-rw-r--r--chrome/browser/cocoa/bookmark_tree_controller.mm253
-rw-r--r--chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm439
-rw-r--r--chrome/browser/cocoa/bookmark_tree_controller_unittest.mm186
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.mm3
-rwxr-xr-xchrome/chrome_browser.gypi8
-rw-r--r--chrome/chrome_dll.gypi1
-rwxr-xr-xchrome/chrome_tests.gypi3
18 files changed, 3347 insertions, 83 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index cd34c8e..321e85d 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5984,6 +5984,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
Recently Closed
</message>
<!-- Bookmarks menu -->
+ <message name="IDS_BOOKMARK_MANAGER_MAC" desc="The Mac menu item for opening the bookmark manager, in the bookmark menu.">
+ Bookmark Manager
+ </message>
<message name="IDS_BOOKMARK_CURRENT_PAGE_MAC" desc="The Mac menu item for bookmarking the current page in the bookmark menu.">
Bookmark This Page...
</message>
diff --git a/chrome/app/nibs/BookmarkManager.xib b/chrome/app/nibs/BookmarkManager.xib
new file mode 100644
index 0000000..63f72bd
--- /dev/null
+++ b/chrome/app/nibs/BookmarkManager.xib
@@ -0,0 +1,1535 @@
+<?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" id="9"/>
+ <integer value="7"/>
+ </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">BookmarkManagerController</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="801612057">
+ <int key="NSWindowStyleMask">15</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{915, 545}, {689, 592}}</string>
+ <int key="NSWTFlags">880280576</int>
+ <string key="NSWindowTitle">^IDS_BOOKMARK_MANAGER_TITLE</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <object class="NSToolbar" key="NSViewClass" id="1046399320">
+ <object class="NSMutableString" key="NSToolbarIdentifier">
+ <characters key="NS.bytes">20D49B48-6DB8-4131-A3FF-BF487B04ABF6</characters>
+ </object>
+ <nil key="NSToolbarDelegate"/>
+ <bool key="NSToolbarPrefersToBeShown">NO</bool>
+ <bool key="NSToolbarShowsBaselineSeparator">YES</bool>
+ <bool key="NSToolbarAllowsUserCustomization">YES</bool>
+ <bool key="NSToolbarAutosavesConfiguration">YES</bool>
+ <int key="NSToolbarDisplayMode">2</int>
+ <int key="NSToolbarSizeMode">2</int>
+ <object class="NSMutableDictionary" key="NSToolbarIBIdentifiedItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>19533CC3-98F5-4A6C-B821-B785FC97D55D</string>
+ <string>83403F3E-2F03-4DB5-A1F0-CA564DEFC3CD</string>
+ <string>NSToolbarCustomizeToolbarItem</string>
+ <string>NSToolbarFlexibleSpaceItem</string>
+ <string>NSToolbarSeparatorItem</string>
+ <string>NSToolbarSpaceItem</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSToolbarItem" id="933364437">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">19533CC3-98F5-4A6C-B821-B785FC97D55D</characters>
+ </object>
+ <string key="NSToolbarItemLabel">New Folder</string>
+ <string key="NSToolbarItemPaletteLabel">New Folder</string>
+ <string key="NSToolbarItemToolTip"/>
+ <nil key="NSToolbarItemView"/>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{0, 0}</string>
+ <string key="NSToolbarItemMaxSize">{0, 0}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarItem" id="1000628990">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">83403F3E-2F03-4DB5-A1F0-CA564DEFC3CD</characters>
+ </object>
+ <string key="NSToolbarItemLabel">Search</string>
+ <string key="NSToolbarItemPaletteLabel">Search</string>
+ <string key="NSToolbarItemToolTip"/>
+ <nil key="NSToolbarItemView"/>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{0, 0}</string>
+ <string key="NSToolbarItemMaxSize">{0, 0}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarItem" id="384214618">
+ <string key="NSToolbarItemIdentifier">NSToolbarCustomizeToolbarItem</string>
+ <string key="NSToolbarItemLabel">Customize</string>
+ <string key="NSToolbarItemPaletteLabel">Customize</string>
+ <string key="NSToolbarItemToolTip">Customize Toolbar</string>
+ <nil key="NSToolbarItemView"/>
+ <object class="NSImage" key="NSToolbarItemImage">
+ <int key="NSImageFlags">683671552</int>
+ <string key="NSSize">{32, 32}</string>
+ <object class="NSMutableArray" key="NSReps">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="0" id="8"/>
+ <object class="NSBitmapImageRep">
+ <object class="NSData" key="NSTIFFRepresentation">
+ <bytes key="NS.bytes">TU0AKgAAEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAICAgbAAAABAAAAAAEBAQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAQEBAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAENDQ0dJSUlW11dXbBpaWnDb29vzyAgIGUPDw8xAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAABsbGyUoKChIHh4ePSkpKUonJycsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDCEJCQoWvr6/i9fX1/fX19f7h4eH82dnZ+YODg9sYGBg8
+AAAAAAAAAAAAAAAAAAAAAAAAAAJFRUV6ZGRkvf39/f/+/v7//////0NDQ7QAAAAEAAAAAAAAAAAAAAAA
+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
+AAAACQAAABAAAAAYAAAAIAAAACoAAAAxAAAANgAAADkAAAA4AQEBOQAAAC8AAAAnAAAAHQAAABUAAAAO
+AAAACgAAAAsAAAAPAAAAFwAAACAAAAAqAAAAMQAAADQAAAAzAAAALQAAACQAAAAbAAAAEgAAAAsAAAAA
+AAAAAAAAAAQAAAAJAAAAEAAAABgAAAAgAAAAKgAAADEAAAA2AAAAOQAAADgAAAA1AAAALwAAACcAAAAd
+AAAAFQAAAA4AAAAKAAAACwAAAA8AAAAXAAAAIAAAACoAAAAxAAAANAAAADMAAAAtAAAAJAAAABsAAAAS
+AAAACwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0BAAADAAAAAQAgAAABAQADAAAAAQAgAAABAgADAAAABAAA
+EKoBAwADAAAAAQABAAABBgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAE
+AAABFgADAAAAAQD8AAABFwAEAAAAAQAAEAABHAADAAAAAQABAAABUgADAAAAAQABAAABUwADAAAABAAA
+ELIAAAAAAAgACAAIAAgAAQABAAEAAQ</bytes>
+ </object>
+ </object>
+ </object>
+ <object class="NSArray">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="8"/>
+ <object class="NSBitmapImageRep">
+ <object class="NSData" key="NSTIFFRepresentation">
+ <bytes key="NS.bytes">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
+cHlyaWdodCBBcHBsZSwgSW5jLiwgMjAxMAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MCAwAA</bytes>
+ </object>
+ </object>
+ <nil key="NSToolbarItemTarget"/>
+ <string key="NSToolbarItemAction">runToolbarCustomizationPalette:</string>
+ <string key="NSToolbarItemMinSize">{0, 0}</string>
+ <string key="NSToolbarItemMaxSize">{0, 0}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarFlexibleSpaceItem" id="52444271">
+ <string key="NSToolbarItemIdentifier">NSToolbarFlexibleSpaceItem</string>
+ <string key="NSToolbarItemLabel"/>
+ <string key="NSToolbarItemPaletteLabel">Flexible Space</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <nil key="NSToolbarItemView"/>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{1, 5}</string>
+ <string key="NSToolbarItemMaxSize">{20000, 32}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ <object class="NSMenuItem" key="NSToolbarItemMenuFormRepresentation">
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="359971663">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="412846030">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSToolbarSeparatorItem" id="228408183">
+ <string key="NSToolbarItemIdentifier">NSToolbarSeparatorItem</string>
+ <string key="NSToolbarItemLabel"/>
+ <string key="NSToolbarItemPaletteLabel">Separator</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <nil key="NSToolbarItemView"/>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{12, 5}</string>
+ <string key="NSToolbarItemMaxSize">{12, 1000}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ <object class="NSMenuItem" key="NSToolbarItemMenuFormRepresentation">
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="359971663"/>
+ <reference key="NSMixedImage" ref="412846030"/>
+ </object>
+ </object>
+ <object class="NSToolbarSpaceItem" id="904990067">
+ <string key="NSToolbarItemIdentifier">NSToolbarSpaceItem</string>
+ <string key="NSToolbarItemLabel"/>
+ <string key="NSToolbarItemPaletteLabel">Space</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <nil key="NSToolbarItemView"/>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{32, 5}</string>
+ <string key="NSToolbarItemMaxSize">{32, 32}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ <object class="NSMenuItem" key="NSToolbarItemMenuFormRepresentation">
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="359971663"/>
+ <reference key="NSMixedImage" ref="412846030"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSArray" key="NSToolbarIBAllowedItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="228408183"/>
+ <reference ref="904990067"/>
+ <reference ref="52444271"/>
+ <reference ref="384214618"/>
+ <reference ref="1000628990"/>
+ <reference ref="933364437"/>
+ </object>
+ <object class="NSMutableArray" key="NSToolbarIBDefaultItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="933364437"/>
+ <reference ref="52444271"/>
+ <reference ref="1000628990"/>
+ </object>
+ <object class="NSMutableArray" key="NSToolbarIBSelectableItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <string key="NSWindowContentMinSize">{500, 250}</string>
+ <object class="NSView" key="NSWindowView" id="775220953">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSSplitView" id="8907081">
+ <reference key="NSNextResponder" ref="775220953"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSScrollView" id="251317961">
+ <reference key="NSNextResponder" ref="8907081"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSClipView" id="764939157">
+ <reference key="NSNextResponder" ref="251317961"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableView" id="580246752">
+ <reference key="NSNextResponder" ref="764939157"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrameSize">{142, 592}</string>
+ <reference key="NSSuperview" ref="764939157"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="_NSCornerView" key="NSCornerView">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-26, 0}, {16, 17}}</string>
+ </object>
+ <object class="NSMutableArray" key="NSTableColumns">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableColumn" id="1069362144">
+ <string key="NSIdentifier">name</string>
+ <double key="NSWidth">1.390000e+02</double>
+ <double key="NSMinWidth">2.000000e+01</double>
+ <double key="NSMaxWidth">1.000000e+04</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628096</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">Group</string>
+ <object class="NSFont" key="NSSupport" id="26">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">1.100000e+01</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="317609481">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">headerTextColor</string>
+ <object class="NSColor" key="NSColor" id="420147826">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="987232547">
+ <int key="NSCellFlags">337772096</int>
+ <int key="NSCellFlags2">133120</int>
+ <string key="NSContents">Text Cell</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="580246752"/>
+ <object class="NSColor" key="NSBackgroundColor" id="774691543">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2OQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="220007638">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <reference key="NSColor" ref="420147826"/>
+ </object>
+ </object>
+ <int key="NSResizingMask">1</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <reference key="NSTableView" ref="580246752"/>
+ </object>
+ </object>
+ <double key="NSIntercellSpacingWidth">3.000000e+00</double>
+ <double key="NSIntercellSpacingHeight">2.000000e+00</double>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">_sourceListBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">1</int>
+ <bytes key="NSRGB">MC44MzkyMTU3IDAuODY2NjY2NjcgMC44OTgwMzkyMgA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSGridColor" id="173030864">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">gridColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC41AA</bytes>
+ </object>
+ </object>
+ <double key="NSRowHeight">1.600000e+01</double>
+ <int key="NSTvFlags">-767557632</int>
+ <int key="NSColumnAutoresizingStyle">4</int>
+ <int key="NSDraggingSourceMaskForLocal">15</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ <int key="NSTableViewSelectionHighlightStyle">1</int>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 1}, {142, 592}}</string>
+ <reference key="NSSuperview" ref="251317961"/>
+ <reference key="NSNextKeyView" ref="580246752"/>
+ <reference key="NSDocView" ref="580246752"/>
+ <reference key="NSBGColor" ref="774691543"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="865256551">
+ <reference key="NSNextResponder" ref="251317961"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{128, 1}, {15, 592}}</string>
+ <reference key="NSSuperview" ref="251317961"/>
+ <reference key="NSTarget" ref="251317961"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSPercent">9.983137e-01</double>
+ </object>
+ <object class="NSScroller" id="752357220">
+ <reference key="NSNextResponder" ref="251317961"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-100, -100}, {223, 15}}</string>
+ <reference key="NSSuperview" ref="251317961"/>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="251317961"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSPercent">9.958159e-01</double>
+ </object>
+ </object>
+ <string key="NSFrameSize">{144, 594}</string>
+ <reference key="NSSuperview" ref="8907081"/>
+ <reference key="NSNextKeyView" ref="764939157"/>
+ <int key="NSsFlags">530</int>
+ <reference key="NSVScroller" ref="865256551"/>
+ <reference key="NSHScroller" ref="752357220"/>
+ <reference key="NSContentView" ref="764939157"/>
+ <bytes key="NSScrollAmts">QSAAAEEgAABBkAAAQZAAAA</bytes>
+ </object>
+ <object class="NSScrollView" id="111232465">
+ <reference key="NSNextResponder" ref="8907081"/>
+ <int key="NSvFlags">274</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSClipView" id="416243018">
+ <reference key="NSNextResponder" ref="111232465"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSOutlineView" id="105944579">
+ <reference key="NSNextResponder" ref="416243018"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{543, 576}</string>
+ <reference key="NSSuperview" ref="416243018"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTableHeaderView" key="NSHeaderView" id="833839723">
+ <reference key="NSNextResponder" ref="682782591"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{543, 17}</string>
+ <reference key="NSSuperview" ref="682782591"/>
+ <reference key="NSTableView" ref="105944579"/>
+ </object>
+ <object class="_NSCornerView" key="NSCornerView" id="401707793">
+ <reference key="NSNextResponder" ref="111232465"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-26, 0}, {16, 17}}</string>
+ <reference key="NSSuperview" ref="111232465"/>
+ </object>
+ <object class="NSMutableArray" key="NSTableColumns">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTableColumn" id="502561775">
+ <string key="NSIdentifier">title</string>
+ <double key="NSWidth">3.210000e+02</double>
+ <double key="NSMinWidth">1.600000e+01</double>
+ <double key="NSMaxWidth">1.000000e+03</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628096</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">^IDS_BOOKMARK_TABLE_TITLE</string>
+ <reference key="NSSupport" ref="26"/>
+ <object class="NSColor" key="NSBackgroundColor" id="41737130">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
+ </object>
+ <reference key="NSTextColor" ref="317609481"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="485613605">
+ <int key="NSCellFlags">337772096</int>
+ <int key="NSCellFlags2">133120</int>
+ <string key="NSContents">Text Cell</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="105944579"/>
+ <reference key="NSBackgroundColor" ref="774691543"/>
+ <reference key="NSTextColor" ref="220007638"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="105944579"/>
+ </object>
+ <object class="NSTableColumn" id="930615590">
+ <string key="NSIdentifier">url</string>
+ <double key="NSWidth">2.160000e+02</double>
+ <double key="NSMinWidth">4.000000e+01</double>
+ <double key="NSMaxWidth">1.000000e+03</double>
+ <object class="NSTableHeaderCell" key="NSHeaderCell">
+ <int key="NSCellFlags">75628096</int>
+ <int key="NSCellFlags2">2048</int>
+ <string key="NSContents">^IDS_BOOKMARK_TABLE_URL</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSBackgroundColor" ref="41737130"/>
+ <reference key="NSTextColor" ref="317609481"/>
+ </object>
+ <object class="NSTextFieldCell" key="NSDataCell" id="294074504">
+ <int key="NSCellFlags">337772096</int>
+ <int key="NSCellFlags2">133120</int>
+ <string key="NSContents">Text Cell</string>
+ <reference key="NSSupport" ref="26"/>
+ <reference key="NSControlView" ref="105944579"/>
+ <reference key="NSBackgroundColor" ref="774691543"/>
+ <reference key="NSTextColor" ref="220007638"/>
+ </object>
+ <int key="NSResizingMask">3</int>
+ <bool key="NSIsResizeable">YES</bool>
+ <bool key="NSIsEditable">YES</bool>
+ <reference key="NSTableView" ref="105944579"/>
+ </object>
+ </object>
+ <double key="NSIntercellSpacingWidth">3.000000e+00</double>
+ <double key="NSIntercellSpacingHeight">2.000000e+00</double>
+ <object class="NSColor" key="NSBackgroundColor" id="497939779">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ <reference key="NSGridColor" ref="173030864"/>
+ <double key="NSRowHeight">1.600000e+01</double>
+ <int key="NSTvFlags">-608174080</int>
+ <string key="NSAutosaveName">bookmarks</string>
+ <int key="NSColumnAutoresizingStyle">5</int>
+ <int key="NSDraggingSourceMaskForLocal">15</int>
+ <int key="NSDraggingSourceMaskForNonLocal">0</int>
+ <bool key="NSAllowsTypeSelect">YES</bool>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 17}, {543, 576}}</string>
+ <reference key="NSSuperview" ref="111232465"/>
+ <reference key="NSNextKeyView" ref="105944579"/>
+ <reference key="NSDocView" ref="105944579"/>
+ <reference key="NSBGColor" ref="774691543"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <object class="NSScroller" id="585875894">
+ <reference key="NSNextResponder" ref="111232465"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{224, 17}, {15, 102}}</string>
+ <reference key="NSSuperview" ref="111232465"/>
+ <reference key="NSTarget" ref="111232465"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSCurValue">3.700000e+01</double>
+ <double key="NSPercent">1.390978e-01</double>
+ </object>
+ <object class="NSScroller" id="1062246906">
+ <reference key="NSNextResponder" ref="111232465"/>
+ <int key="NSvFlags">-2147483392</int>
+ <string key="NSFrame">{{-100, -100}, {223, 15}}</string>
+ <reference key="NSSuperview" ref="111232465"/>
+ <int key="NSsFlags">1</int>
+ <reference key="NSTarget" ref="111232465"/>
+ <string key="NSAction">_doScroller:</string>
+ <double key="NSPercent">5.714286e-01</double>
+ </object>
+ <object class="NSClipView" id="682782591">
+ <reference key="NSNextResponder" ref="111232465"/>
+ <int key="NSvFlags">2304</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="833839723"/>
+ </object>
+ <string key="NSFrame">{{1, 0}, {543, 17}}</string>
+ <reference key="NSSuperview" ref="111232465"/>
+ <reference key="NSNextKeyView" ref="833839723"/>
+ <reference key="NSDocView" ref="833839723"/>
+ <reference key="NSBGColor" ref="774691543"/>
+ <int key="NScvFlags">4</int>
+ </object>
+ <reference ref="401707793"/>
+ </object>
+ <string key="NSFrame">{{145, 0}, {545, 594}}</string>
+ <reference key="NSSuperview" ref="8907081"/>
+ <reference key="NSNextKeyView" ref="416243018"/>
+ <int key="NSsFlags">530</int>
+ <reference key="NSVScroller" ref="585875894"/>
+ <reference key="NSHScroller" ref="1062246906"/>
+ <reference key="NSContentView" ref="416243018"/>
+ <reference key="NSHeaderClipView" ref="682782591"/>
+ <reference key="NSCornerView" ref="401707793"/>
+ <bytes key="NSScrollAmts">QSAAAEEgAABBkAAAQZAAAA</bytes>
+ </object>
+ </object>
+ <string key="NSFrame">{{-1, -2}, {690, 594}}</string>
+ <reference key="NSSuperview" ref="775220953"/>
+ <bool key="NSIsVertical">YES</bool>
+ <int key="NSDividerStyle">2</int>
+ </object>
+ </object>
+ <string key="NSFrameSize">{689, 592}</string>
+ <reference key="NSSuperview"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {2560, 1578}}</string>
+ <string key="NSMinSize">{500, 272}</string>
+ <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
+ <string key="NSFrameAutosaveName">bookmark_manager</string>
+ </object>
+ <object class="NSCustomObject" id="221366305">
+ <string key="NSClassName">BookmarkTreeController</string>
+ </object>
+ <object class="NSCustomObject" id="506845861">
+ <string key="NSClassName">BookmarkGroupsController</string>
+ </object>
+ <object class="NSCustomView" id="372717701">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">268</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSSearchField" id="159839204">
+ <reference key="NSNextResponder" ref="372717701"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{38, 102}, {165, 22}}</string>
+ <reference key="NSSuperview" ref="372717701"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSSearchFieldCell" key="NSCell" id="1043792166">
+ <int key="NSCellFlags">343014976</int>
+ <int key="NSCellFlags2">268436480</int>
+ <string key="NSContents">^IDS_BOOKMARK_MANAGER_SEARCH_TITLE</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">1.300000e+01</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <string key="NSPlaceholderString">Search</string>
+ <reference key="NSControlView" ref="159839204"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <int key="NSTextBezelStyle">1</int>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <reference key="NSColor" ref="497939779"/>
+ </object>
+ <reference key="NSTextColor" ref="220007638"/>
+ <object class="NSButtonCell" key="NSSearchButtonCell">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">search</string>
+ <string key="NSAction">_searchFieldSearch:</string>
+ <reference key="NSTarget" ref="1043792166"/>
+ <reference key="NSControlView" ref="159839204"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">0</int>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <object class="NSButtonCell" key="NSCancelButtonCell">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">clear</string>
+ <object class="NSMutableArray" key="NSAccessibilityOverriddenAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableDictionary">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>AXDescription</string>
+ <string>NSAccessibilityEncodedAttributesValueType</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>cancel</string>
+ <reference ref="9"/>
+ </object>
+ </object>
+ </object>
+ <string key="NSAction">_searchFieldCancel:</string>
+ <reference key="NSTarget" ref="1043792166"/>
+ <reference key="NSControlView" ref="159839204"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">0</int>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <int key="NSMaximumRecents">10</int>
+ <bytes key="NSSearchFieldFlags">CAAAAA</bytes>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{277, 169}</string>
+ <reference key="NSSuperview"/>
+ <string key="NSClassName">NSView</string>
+ </object>
+ <object class="NSCustomObject" id="16155636">
+ <string key="NSClassName">ChromeUILocalizer</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">dataSource</string>
+ <reference key="source" ref="105944579"/>
+ <reference key="destination" ref="221366305"/>
+ </object>
+ <int key="connectionID">34</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="580246752"/>
+ <reference key="destination" ref="506845861"/>
+ </object>
+ <int key="connectionID">36</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="105944579"/>
+ <reference key="destination" ref="221366305"/>
+ </object>
+ <int key="connectionID">39</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="801612057"/>
+ </object>
+ <int key="connectionID">40</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="801612057"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">41</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1046399320"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">47</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">searchFieldChanged:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="159839204"/>
+ </object>
+ <int key="connectionID">48</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">groupsTable_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="580246752"/>
+ </object>
+ <int key="connectionID">49</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">treeController_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="221366305"/>
+ </object>
+ <int key="connectionID">51</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">toolbarSearchView_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="159839204"/>
+ </object>
+ <int key="connectionID">52</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">outline_</string>
+ <reference key="source" ref="221366305"/>
+ <reference key="destination" ref="105944579"/>
+ </object>
+ <int key="connectionID">53</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">groupsTable_</string>
+ <reference key="source" ref="506845861"/>
+ <reference key="destination" ref="580246752"/>
+ </object>
+ <int key="connectionID">54</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">dataSource</string>
+ <reference key="source" ref="580246752"/>
+ <reference key="destination" ref="506845861"/>
+ </object>
+ <int key="connectionID">56</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">tableClicked:</string>
+ <reference key="source" ref="506845861"/>
+ <reference key="destination" ref="580246752"/>
+ </object>
+ <int key="connectionID">57</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">groupsController_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="506845861"/>
+ </object>
+ <int key="connectionID">58</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">manager_</string>
+ <reference key="source" ref="221366305"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">59</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">manager_</string>
+ <reference key="source" ref="506845861"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">60</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">owner_</string>
+ <reference key="source" ref="16155636"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">62</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="904321106">
+ <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="904321106"/>
+ <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="904321106"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1004"/>
+ <reference key="parent" ref="904321106"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">1</int>
+ <reference key="object" ref="801612057"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1046399320"/>
+ <reference ref="775220953"/>
+ </object>
+ <reference key="parent" ref="904321106"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">3</int>
+ <reference key="object" ref="221366305"/>
+ <reference key="parent" ref="904321106"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">4</int>
+ <reference key="object" ref="506845861"/>
+ <reference key="parent" ref="904321106"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="372717701"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="159839204"/>
+ </object>
+ <reference key="parent" ref="904321106"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">6</int>
+ <reference key="object" ref="159839204"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1043792166"/>
+ </object>
+ <reference key="parent" ref="372717701"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">7</int>
+ <reference key="object" ref="1043792166"/>
+ <reference key="parent" ref="159839204"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">8</int>
+ <reference key="object" ref="1046399320"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="933364437"/>
+ <reference ref="1000628990"/>
+ <reference ref="384214618"/>
+ <reference ref="52444271"/>
+ <reference ref="904990067"/>
+ <reference ref="228408183"/>
+ </object>
+ <reference key="parent" ref="801612057"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">9</int>
+ <reference key="object" ref="775220953"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="8907081"/>
+ </object>
+ <reference key="parent" ref="801612057"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="8907081"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="111232465"/>
+ <reference ref="251317961"/>
+ </object>
+ <reference key="parent" ref="775220953"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="111232465"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="585875894"/>
+ <reference ref="1062246906"/>
+ <reference ref="105944579"/>
+ <reference ref="833839723"/>
+ </object>
+ <reference key="parent" ref="8907081"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="251317961"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="865256551"/>
+ <reference ref="752357220"/>
+ <reference ref="580246752"/>
+ </object>
+ <reference key="parent" ref="8907081"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">14</int>
+ <reference key="object" ref="865256551"/>
+ <reference key="parent" ref="251317961"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">15</int>
+ <reference key="object" ref="752357220"/>
+ <reference key="parent" ref="251317961"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">16</int>
+ <reference key="object" ref="580246752"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1069362144"/>
+ </object>
+ <reference key="parent" ref="251317961"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">17</int>
+ <reference key="object" ref="1069362144"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="987232547"/>
+ </object>
+ <reference key="parent" ref="580246752"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">18</int>
+ <reference key="object" ref="987232547"/>
+ <reference key="parent" ref="1069362144"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="585875894"/>
+ <reference key="parent" ref="111232465"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">20</int>
+ <reference key="object" ref="1062246906"/>
+ <reference key="parent" ref="111232465"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">21</int>
+ <reference key="object" ref="105944579"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="502561775"/>
+ <reference ref="930615590"/>
+ </object>
+ <reference key="parent" ref="111232465"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">22</int>
+ <reference key="object" ref="833839723"/>
+ <reference key="parent" ref="111232465"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="502561775"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="485613605"/>
+ </object>
+ <reference key="parent" ref="105944579"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="930615590"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="294074504"/>
+ </object>
+ <reference key="parent" ref="105944579"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">25</int>
+ <reference key="object" ref="294074504"/>
+ <reference key="parent" ref="930615590"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">26</int>
+ <reference key="object" ref="485613605"/>
+ <reference key="parent" ref="502561775"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">27</int>
+ <reference key="object" ref="933364437"/>
+ <reference key="parent" ref="1046399320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">28</int>
+ <reference key="object" ref="1000628990"/>
+ <reference key="parent" ref="1046399320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="384214618"/>
+ <reference key="parent" ref="1046399320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">30</int>
+ <reference key="object" ref="52444271"/>
+ <reference key="parent" ref="1046399320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">31</int>
+ <reference key="object" ref="904990067"/>
+ <reference key="parent" ref="1046399320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">32</int>
+ <reference key="object" ref="228408183"/>
+ <reference key="parent" ref="1046399320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">61</int>
+ <reference key="object" ref="16155636"/>
+ <reference key="parent" ref="904321106"/>
+ </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.editorWindowContentRectSynchronizationRect</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>14.IBPluginDependency</string>
+ <string>15.IBPluginDependency</string>
+ <string>16.CustomClassName</string>
+ <string>16.IBPluginDependency</string>
+ <string>17.IBPluginDependency</string>
+ <string>18.CustomClassName</string>
+ <string>18.IBPluginDependency</string>
+ <string>19.IBPluginDependency</string>
+ <string>20.IBPluginDependency</string>
+ <string>21.CustomClassName</string>
+ <string>21.IBPluginDependency</string>
+ <string>22.IBPluginDependency</string>
+ <string>23.IBPluginDependency</string>
+ <string>24.IBPluginDependency</string>
+ <string>25.IBPluginDependency</string>
+ <string>26.CustomClassName</string>
+ <string>26.IBPluginDependency</string>
+ <string>27.IBPluginDependency</string>
+ <string>28.IBPluginDependency</string>
+ <string>28.designableToolbarItemIdentifier</string>
+ <string>29.IBPluginDependency</string>
+ <string>5.IBEditorWindowLastContentRect</string>
+ <string>5.IBPluginDependency</string>
+ <string>6.IBPluginDependency</string>
+ <string>61.IBPluginDependency</string>
+ <string>7.IBPluginDependency</string>
+ <string>8.IBEditorWindowLastContentRect</string>
+ <string>8.IBPluginDependency</string>
+ <string>8.designableToolbarIdentifier</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>{{112, 245}, {689, 592}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{112, 245}, {689, 592}}</string>
+ <boolean value="NO"/>
+ <string>{{33, 99}, {480, 360}}</string>
+ <boolean value="YES"/>
+ <string>{3.40282e+38, 3.40282e+38}</string>
+ <string>{500, 250}</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>BookmarksTableView</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>ImageAndTextCell</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>BookmarksOutlineView</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>ImageAndTextCell</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>search</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{614, 49}, {277, 169}}</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>{{92, 786}, {617, 0}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>bookmarksToolbar</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">62</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarkGroupsController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">tableClicked:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>groupsTable_</string>
+ <string>manager_</string>
+ <string>selectedGroup_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSTableView</string>
+ <string>BookmarkManagerController</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="867038439">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/bookmark_groups_controller.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarkManagerController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">searchFieldChanged:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>groupsController_</string>
+ <string>groupsTable_</string>
+ <string>toolbarSearchView_</string>
+ <string>treeController_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>BookmarkGroupsController</string>
+ <string>NSTableView</string>
+ <string>NSSearchField</string>
+ <string>BookmarkTreeController</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/bookmark_manager_controller.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarkTreeController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>copy:</string>
+ <string>cut:</string>
+ <string>delete:</string>
+ <string>paste:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <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>group_</string>
+ <string>manager_</string>
+ <string>outline_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>BookmarkManagerController</string>
+ <string>NSOutlineView</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="706533809">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/bookmark_tree_controller.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarkTreeController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarksOutlineView</string>
+ <string key="superclassName">NSOutlineView</string>
+ <reference key="sourceIdentifier" ref="706533809"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarksOutlineView</string>
+ <string key="superclassName">NSOutlineView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarksTableView</string>
+ <string key="superclassName">NSTableView</string>
+ <reference key="sourceIdentifier" ref="867038439"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarksTableView</string>
+ <string key="superclassName">NSTableView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">ChromeUILocalizer</string>
+ <string key="superclassName">GTMUILocalizer</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/ui_localizer.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">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">ImageAndTextCell</string>
+ <string key="superclassName">NSTextFieldCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">../third_party/apple/ImageAndTextCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">ImageAndTextCell</string>
+ <string key="superclassName">NSTextFieldCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </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/app/nibs/MainMenu.xib b/chrome/app/nibs/MainMenu.xib
index 7a0e62f..4fabcb9 100644
--- a/chrome/app/nibs/MainMenu.xib
+++ b/chrome/app/nibs/MainMenu.xib
@@ -8,7 +8,7 @@
<string key="IBDocument.HIToolboxVersion">353.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="296"/>
+ <integer value="504"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -954,6 +954,27 @@
<string key="NSTitle">^IDS_BOOKMARKS_MENU_MAC</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="926580029">
+ <reference key="NSMenu" ref="891828782"/>
+ <string key="NSTitle">^IDS_BOOKMARK_MANAGER</string>
+ <string key="NSKeyEquiv">b</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="353210768"/>
+ <reference key="NSMixedImage" ref="549394948"/>
+ <int key="NSTag">40011</int>
+ </object>
+ <object class="NSMenuItem" id="226650579">
+ <reference key="NSMenu" ref="891828782"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="353210768"/>
+ <reference key="NSMixedImage" ref="549394948"/>
+ <int key="NSTag">35000</int>
+ </object>
<object class="NSMenuItem" id="399860348">
<reference key="NSMenu" ref="891828782"/>
<string key="NSTitle">^IDS_BOOKMARK_CURRENT_PAGE_MAC</string>
@@ -1707,13 +1728,21 @@
</object>
<int key="connectionID">671</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">commandDispatch:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="926580029"/>
+ </object>
+ <int key="connectionID">673</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="953662269">
+ <object class="NSArray" key="object" id="542358269">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="1048"/>
@@ -1722,19 +1751,19 @@
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="1021"/>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
<string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="1014"/>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="1050"/>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
@@ -1751,7 +1780,7 @@
<reference ref="586577488"/>
<reference ref="445514911"/>
</object>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
<string key="objectName">Main Menu</string>
</object>
<object class="IBObjectRecord">
@@ -2190,7 +2219,7 @@
<object class="IBObjectRecord">
<int key="objectID">373</int>
<reference key="object" ref="163992474"/>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">449</int>
@@ -2281,7 +2310,7 @@
<object class="IBObjectRecord">
<int key="objectID">483</int>
<reference key="object" ref="168151378"/>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">492</int>
@@ -2342,6 +2371,8 @@
<reference ref="505033846"/>
<reference ref="399860348"/>
<reference ref="774017921"/>
+ <reference ref="926580029"/>
+ <reference ref="226650579"/>
</object>
<reference key="parent" ref="299901009"/>
</object>
@@ -2494,7 +2525,7 @@
<object class="IBObjectRecord">
<int key="objectID">641</int>
<reference key="object" ref="979722531"/>
- <reference key="parent" ref="953662269"/>
+ <reference key="parent" ref="542358269"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">648</int>
@@ -2551,6 +2582,16 @@
<reference key="object" ref="737490158"/>
<reference key="parent" ref="963351320"/>
</object>
+ <object class="IBObjectRecord">
+ <int key="objectID">672</int>
+ <reference key="object" ref="926580029"/>
+ <reference key="parent" ref="891828782"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">674</int>
+ <reference key="object" ref="226650579"/>
+ <reference key="parent" ref="891828782"/>
+ </object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@@ -2745,6 +2786,8 @@
<string>665.IBPluginDependency</string>
<string>669.IBPluginDependency</string>
<string>670.IBPluginDependency</string>
+ <string>672.IBPluginDependency</string>
+ <string>674.IBPluginDependency</string>
<string>72.IBPluginDependency</string>
<string>72.ImportedFromIB2</string>
<string>73.IBPluginDependency</string>
@@ -2865,17 +2908,17 @@
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
- <string>{{1382, 97}, {323, 183}}</string>
+ <string>{{1254, 68}, {326, 183}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{{525, 802}, {197, 73}}</string>
- <string>{{-317, 706}, {1578, 20}}</string>
+ <string>{{64, 251}, {1578, 20}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>{74, 862}</string>
<string>{{11, 977}, {478, 20}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{270, 493}, {383, 213}}</string>
+ <string>{{651, 38}, {383, 213}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{475, 832}, {234, 43}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -2905,7 +2948,7 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{965, 284}, {361, 53}}</string>
+ <string>{{1026, 168}, {361, 83}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
@@ -2916,7 +2959,7 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{761, 184}, {301, 153}}</string>
+ <string>{{825, 98}, {304, 153}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -2961,6 +3004,8 @@
<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>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
@@ -3006,7 +3051,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">671</int>
+ <int key="maxID">674</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -3048,6 +3093,102 @@
</object>
</object>
<object class="IBPartialClassDescription">
+ <string key="className">BookmarkGroupsController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">tableClicked:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>groupsTable_</string>
+ <string>manager_</string>
+ <string>selectedGroup_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSTableView</string>
+ <string>BookmarkManagerController</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/bookmark_groups_controller.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarkManagerController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">searchFieldChanged:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>groupsController_</string>
+ <string>groupsTable_</string>
+ <string>toolbarSearchView_</string>
+ <string>treeController_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>BookmarkGroupsController</string>
+ <string>NSTableView</string>
+ <string>NSSearchField</string>
+ <string>BookmarkTreeController</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/bookmark_manager_controller.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BookmarkTreeController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>copy:</string>
+ <string>cut:</string>
+ <string>delete:</string>
+ <string>paste:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <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>group_</string>
+ <string>manager_</string>
+ <string>outline_</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>BookmarkManagerController</string>
+ <string>NSOutlineView</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/bookmark_tree_controller.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
<string key="className">BrowserCrApplication</string>
<string key="superclassName">CrApplication</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
@@ -3112,31 +3253,6 @@
</object>
</object>
<object class="IBPartialClassDescription">
- <string key="className">ExtensionShelfController</string>
- <string key="superclassName">NSViewController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>hide:</string>
- <string>show:</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">
- <string key="NS.key.0">resizeDelegate_</string>
- <string key="NS.object.0">id</string>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">browser/cocoa/extension_shelf_controller.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
<string key="className">FirstResponder</string>
<string key="superclassName">NSObject</string>
<object class="NSMutableDictionary" key="actions">
@@ -3216,46 +3332,6 @@
<string key="minorKey">browser/cocoa/nswindow_local_state.h</string>
</object>
</object>
- <object class="IBPartialClassDescription">
- <string key="className">TabController</string>
- <string key="superclassName">NSViewController</string>
- <object class="NSMutableDictionary" key="actions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>closeTab:</string>
- <string>commandDispatch:</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>contextMenu_</string>
- <string>iconView_</string>
- <string>target_</string>
- <string>titleView_</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSButton</string>
- <string>NSMenu</string>
- <string>NSView</string>
- <string>id</string>
- <string>NSTextField</string>
- </object>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">browser/cocoa/tab_controller.h</string>
- </object>
- </object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index fac7afd..671f73f 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -2541,9 +2541,7 @@ void Browser::InitCommandState() {
command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
command_updater_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
-#if !defined(OS_MACOSX) // http://crbug.com/13149
command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
-#endif
command_updater_.UpdateCommandEnabled(IDC_SHOW_EXTENSION_SHELF, true);
command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
diff --git a/chrome/browser/cocoa/bookmark_groups_controller.h b/chrome/browser/cocoa/bookmark_groups_controller.h
new file mode 100644
index 0000000..ccd9e32
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_groups_controller.h
@@ -0,0 +1,52 @@
+// 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>
+
+@class BookmarkManagerController;
+class BookmarkModel;
+class BookmarkNode;
+
+
+// Controller for the bookmark group list (the left pane).
+@interface BookmarkGroupsController : NSObject {
+ @private
+ IBOutlet NSTableView* groupsTable_;
+ IBOutlet BookmarkManagerController* manager_;
+
+ NSMutableArray* groups_; // array of node items ('id's)
+ id selectedGroup_; // selected item from groups
+}
+
+// The ordered list of groups shown in the table view. Observable.
+// Each item is an 'id', as vended by BookmarkManagerController's -itemFromNode:
+@property (copy) NSArray* groups;
+// The item in -groups currently selected in the table view. Observable.
+@property (retain) id selectedGroup;
+
+// Called by the table view when a row is clicked.
+- (IBAction)tableClicked:(id)sender;
+
+// Reloads the groups property and table contents from the data model.
+- (void)reload;
+
+// Called by BookmarkManagerController to notify that the data model's changed.
+- (void)nodeChanged:(const BookmarkNode*)node
+ childrenChanged:(BOOL)childrenChanged;
+
+@end
+
+
+// Exposed only for unit tests.
+@interface BookmarkGroupsController (UnitTesting)
+
+@property (readonly) NSTableView* groupsTable;
+
+@end
+
+
+
+// Table view for bookmark group list; handles Cut/Copy/Paste and Delete key.
+@interface BookmarksTableView : NSTableView
+@end
diff --git a/chrome/browser/cocoa/bookmark_groups_controller.mm b/chrome/browser/cocoa/bookmark_groups_controller.mm
new file mode 100644
index 0000000..e6b14f3
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_groups_controller.mm
@@ -0,0 +1,165 @@
+// 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 "chrome/browser/cocoa/bookmark_groups_controller.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/cocoa/bookmark_manager_controller.h"
+#import "chrome/browser/cocoa/bookmark_tree_controller.h"
+#import "third_party/apple/ImageAndTextCell.h"
+
+
+@interface BookmarkGroupsController ()
+- (void)syncSelection;
+- (void)reload;
+@end
+
+
+@implementation BookmarkGroupsController
+
+@synthesize groups = groups_, selectedGroup = selectedGroup_;
+
+-(void)dealloc {
+ [groups_ release];
+ [selectedGroup_ release];
+ [super dealloc];
+}
+
+// Completely reloads the contents of the table view.
+- (void)reload {
+ NSMutableArray* groups = [NSMutableArray array];
+ BookmarkModel* bookmarkModel = [manager_ bookmarkModel];
+ const BookmarkNode* node = bookmarkModel->GetBookmarkBarNode();
+ [groups addObject:[manager_ itemFromNode:node]];
+ node = bookmarkModel->other_node();
+ for (int i = 0; i < node->GetChildCount(); i++) {
+ const BookmarkNode* child = node->GetChild(i);
+ if (child->is_folder()) {
+ [groups addObject:[manager_ itemFromNode:child]];
+ }
+ }
+ //TODO(snej): Append Recents and Search groups
+
+ if (![groups isEqual:[self groups]]) {
+ [self setGroups:groups];
+ [groupsTable_ reloadData];
+ [self syncSelection];
+ }
+}
+
+// Responds to changes in the bookmark data model.
+- (void)nodeChanged:(const BookmarkNode*)node
+ childrenChanged:(BOOL)childrenChanged {
+ if (node == [manager_ bookmarkModel]->other_node()) {
+ [self reload];
+ }
+}
+
+// Returns the selected BookmarkNode.
+- (const BookmarkNode*)selectedNode {
+ NSInteger row = [groupsTable_ selectedRow];
+ if (row < 0)
+ return NULL;
+ id item = [groups_ objectAtIndex:row];
+ return [manager_ nodeFromItem:item];
+}
+
+- (id)selectedGroup {
+ return selectedGroup_;
+}
+
+- (void)setSelectedGroup:(id)group {
+ [selectedGroup_ autorelease];
+ selectedGroup_ = [group retain];
+
+ NSInteger row = group ? [groups_ indexOfObject:group] : NSNotFound;
+ if (row != NSNotFound)
+ [groupsTable_ selectRow:row byExtendingSelection:NO];
+ else
+ [groupsTable_ deselectAll:self];
+}
+
+- (NSTableView*)groupsTable {
+ return groupsTable_;
+}
+
+
+#pragma mark -
+#pragma mark COMMANDS:
+
+
+// Updates the |selectedGroup| property based on the table view's selection.
+- (void)syncSelection {
+ id selGroup = nil;
+ NSInteger row = [groupsTable_ selectedRow];
+ if (row >= 0) {
+ selGroup = [groups_ objectAtIndex:row];
+ if (![selGroup isKindOfClass:[NSValue class]])
+ selGroup = nil;
+ }
+ if (selGroup != [self selectedGroup])
+ [self setSelectedGroup:selGroup];
+}
+
+// Called when a row is clicked; updates the |selectedGroup| property.
+- (IBAction)tableClicked:(id)sender {
+ [self syncSelection];
+}
+
+// The Delete command; also invoked by the delete key.
+- (IBAction)delete:(id)sender {
+ const BookmarkNode* sel = [self selectedNode];
+ if (!sel) {
+ NSBeep();
+ return;
+ }
+ const BookmarkNode* parent = sel->GetParent();
+ [manager_ bookmarkModel]->Remove(parent, parent->IndexOfChild(sel));
+}
+
+
+#pragma mark -
+#pragma mark LIST VIEW:
+
+
+// Returns the number of rows in the table (NSTableView data source).
+- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
+ return [groups_ count];
+}
+
+// Returns the contents of a table cell (NSTableView data source).
+- (id) tableView:(NSTableView*)tableView
+ objectValueForTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)row {
+ id item = [groups_ objectAtIndex:row];
+ return base::SysWideToNSString([manager_ nodeFromItem:item]->GetTitle());
+}
+
+// Sets a table cell's icon before it's drawn (NSTableView delegate).
+- (void)tableView:(NSTableView*)tableView
+ willDisplayCell:(id)cell
+ forTableColumn:(NSTableColumn*)tableColumn
+ row:(NSInteger)row {
+ id item = [groups_ objectAtIndex:row];
+ [(ImageAndTextCell*)cell setImage:[manager_ iconForItem:item]];
+}
+
+@end
+
+
+@implementation BookmarksTableView
+
+- (IBAction)delete:(id)sender {
+ [(BookmarkGroupsController*)[self delegate] delete:sender];
+}
+
+- (void)keyDown:(NSEvent*)event {
+ if ([event keyCode] == 51) // Delete key
+ [self delete:self];
+ else
+ [super keyDown:event];
+}
+
+@end
diff --git a/chrome/browser/cocoa/bookmark_groups_controller_unittest.mm b/chrome/browser/cocoa/bookmark_groups_controller_unittest.mm
new file mode 100644
index 0000000..60427ee
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_groups_controller_unittest.mm
@@ -0,0 +1,79 @@
+// 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/scoped_nsobject.h"
+#import "chrome/browser/cocoa/bookmark_groups_controller.h"
+#import "chrome/browser/cocoa/bookmark_manager_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"
+#include "testing/platform_test.h"
+
+namespace {
+
+class BookmarkGroupsControllerTest : public CocoaTest {
+ public:
+ void SetUp() {
+ CocoaTest::SetUp();
+ manager_ = [BookmarkManagerController showBookmarkManager:
+ browser_test_helper_.profile()];
+ ASSERT_TRUE(manager_);
+ controller_ = [manager_ groupsController];
+ ASSERT_TRUE(controller_);
+ }
+
+ void TearDown() {
+ [manager_ close];
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper browser_test_helper_;
+ BookmarkManagerController* manager_;
+ BookmarkGroupsController* controller_;
+};
+
+TEST_F(BookmarkGroupsControllerTest, Model) {
+ NSArray *groups = [controller_ groups];
+ ASSERT_TRUE(groups);
+ // TODO(snej): Update this next assertion after I add Search and Recents.
+ ASSERT_EQ(1U, [groups count]);
+ id barItem = [groups objectAtIndex:0];
+ BookmarkModel* model = [manager_ bookmarkModel];
+ const BookmarkNode* barNode = model->GetBookmarkBarNode();
+ EXPECT_EQ(barNode, [manager_ nodeFromItem:barItem]);
+
+ // Now add an item to Others:
+ const BookmarkNode* otherNode = model->other_node();
+ const BookmarkNode* wowbagger = model->AddGroup(otherNode, 0, L"Wowbagger");
+
+ groups = [controller_ groups];
+ ASSERT_TRUE(groups);
+ ASSERT_EQ(2U, [groups count]);
+ id wowbaggerItem = [groups objectAtIndex:1];
+ EXPECT_EQ(wowbagger, [manager_ nodeFromItem:wowbaggerItem]);
+
+ // Now remove it:
+ model->Remove(otherNode, 0);
+
+ groups = [controller_ groups];
+ ASSERT_TRUE(groups);
+ ASSERT_EQ(1U, [groups count]);
+ ASSERT_EQ(barItem, [groups objectAtIndex:0]);
+}
+
+TEST_F(BookmarkGroupsControllerTest, Selection) {
+ // Select nothing:
+ ASSERT_TRUE([controller_ groupsTable]);
+ [controller_ setSelectedGroup:nil];
+ EXPECT_EQ(nil, [controller_ selectedGroup]);
+ EXPECT_EQ(-1, [[controller_ groupsTable] selectedRow]);
+
+ // Select bookmarks bar:
+ id sel = [[controller_ groups] objectAtIndex:0];
+ [controller_ setSelectedGroup:sel];
+ EXPECT_EQ(sel, [controller_ selectedGroup]);
+ EXPECT_EQ(0, [[controller_ groupsTable] selectedRow]);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/bookmark_manager_controller.h b/chrome/browser/cocoa/bookmark_manager_controller.h
new file mode 100644
index 0000000..c5b8b73
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_manager_controller.h
@@ -0,0 +1,63 @@
+// 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"
+
+@class BookmarkGroupsController;
+@class BookmarkTreeController;
+class BookmarkManagerBridge;
+class BookmarkModel;
+class BookmarkNode;
+class Profile;
+
+// Controller for the bookmark manager window. There is at most one instance.
+@interface BookmarkManagerController : NSWindowController {
+ @private
+ IBOutlet NSTableView* groupsTable_;
+ IBOutlet NSSearchField* toolbarSearchView_;
+ IBOutlet BookmarkGroupsController* groupsController_;
+ IBOutlet BookmarkTreeController* treeController_;
+
+ Profile* profile_; // weak
+ BookmarkManagerBridge* bridge_;
+ scoped_nsobject<NSMapTable> nodeMap_;
+ scoped_nsobject<NSImage> folderIcon_;
+ scoped_nsobject<NSImage> defaultFavIcon_;
+}
+
+// Opens the bookmark manager window, or brings it to the front if it's open.
++ (BookmarkManagerController*)showBookmarkManager:(Profile*)profile;
+
+// The BookmarkModel of the manager's Profile.
+@property (readonly) BookmarkModel* bookmarkModel;
+
+// Maps C++ BookmarkNode objects to opaque Objective-C objects.
+// This allows nodes to be stored in NSArrays or NSOutlineViews.
+- (id)itemFromNode:(const BookmarkNode*)node;
+
+// Converse of -nodeFromItem: -- maps an opaque item back to a BookmarkNode.
+- (const BookmarkNode*)nodeFromItem:(id)item;
+
+// Returns the icon to be displayed for an item representing a BookmarkNode.
+// This will be the URL's favicon, a generic page icon, or a folder icon.
+- (NSImage*)iconForItem:(id)item;
+
+// Opens a URL bookmark in a browser tab.
+- (void)openBookmarkItem:(id)item;
+
+// Called by the toolbar search field after the user changes its text.
+- (IBAction)searchFieldChanged:(id)sender;
+
+@end
+
+
+// Exposed only for unit tests.
+@interface BookmarkManagerController (UnitTesting)
+
+- (void)forgetNode:(const BookmarkNode*)node;
+@property (readonly) BookmarkGroupsController* groupsController;
+@property (readonly) BookmarkTreeController* treeController;
+
+@end
diff --git a/chrome/browser/cocoa/bookmark_manager_controller.mm b/chrome/browser/cocoa/bookmark_manager_controller.mm
new file mode 100644
index 0000000..8b39fb6
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_manager_controller.mm
@@ -0,0 +1,261 @@
+// 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 "chrome/browser/cocoa/bookmark_manager_controller.h"
+
+#include "app/resource_bundle.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_model_observer.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#import "chrome/browser/cocoa/bookmark_groups_controller.h"
+#import "chrome/browser/cocoa/bookmark_tree_controller.h"
+#include "chrome/browser/profile.h"
+#include "grit/app_resources.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/skia_utils_mac.h"
+
+
+// There's at most one BookmarkManagerController at a time. This points to it.
+static BookmarkManagerController* sInstance;
+
+
+@interface BookmarkManagerController ()
+- (void)nodeChanged:(const BookmarkNode*)node
+ childrenChanged:(BOOL)childrenChanged;
+@end
+
+
+// Adapter to tell BookmarkManagerController when bookmarks change.
+class BookmarkManagerBridge : public BookmarkModelObserver {
+ public:
+ BookmarkManagerBridge(BookmarkManagerController* manager)
+ :manager_(manager) { }
+
+ virtual void Loaded(BookmarkModel* model) {
+ // Ignore this; model has already loaded by this point.
+ }
+
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ const BookmarkNode* old_parent,
+ int old_index,
+ const BookmarkNode* new_parent,
+ int new_index) {
+ [manager_ nodeChanged:old_parent childrenChanged:YES];
+ [manager_ nodeChanged:new_parent childrenChanged:YES];
+ }
+
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int index) {
+ [manager_ nodeChanged:parent childrenChanged:YES];
+ }
+
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ const BookmarkNode* parent,
+ int old_index,
+ const BookmarkNode* node) {
+ [manager_ nodeChanged:parent childrenChanged:YES];
+ [manager_ forgetNode:node];
+ }
+
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ const BookmarkNode* node) {
+ [manager_ nodeChanged:node childrenChanged:NO];
+ }
+
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ const BookmarkNode* node) {
+ [manager_ nodeChanged:node childrenChanged:NO];
+ }
+
+ virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
+ const BookmarkNode* node) {
+ [manager_ nodeChanged:node childrenChanged:YES];
+ }
+
+ private:
+ BookmarkManagerController* manager_; // weak
+};
+
+
+@implementation BookmarkManagerController
+
+
+// Private instance initialization method.
+- (id)initWithProfile:(Profile*)profile {
+ // Use initWithWindowNibPath:: instead of initWithWindowNibName: so we
+ // can override it in a unit test.
+ NSString* nibPath = [mac_util::MainAppBundle()
+ pathForResource:@"BookmarkManager"
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nibPath owner:self];
+ if (self != nil) {
+ profile_ = profile;
+ bridge_ = new BookmarkManagerBridge(self);
+ profile_->GetBookmarkModel()->AddObserver(bridge_);
+
+ // Initialize some cached icons:
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ folderIcon_.reset([rb.GetNSImageNamed(IDR_BOOKMARK_BAR_FOLDER) retain]);
+ defaultFavIcon_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ if (self == sInstance) {
+ sInstance = nil;
+ }
+ if (bridge_) {
+ profile_->GetBookmarkModel()->RemoveObserver(bridge_);
+ delete bridge_;
+ }
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ [groupsController_ reload];
+ [treeController_ bind:@"group"
+ toObject:groupsController_
+ withKeyPath:@"selectedGroup"
+ options:0];
+}
+
+// can't synthesize category methods, unfortunately
+- (BookmarkGroupsController*)groupsController {
+ return groupsController_;
+}
+
+- (BookmarkTreeController*)treeController {
+ return treeController_;
+}
+
+
+#pragma mark -
+#pragma mark DATA MODEL:
+
+
+// Getter for the |bookmarkModel| property.
+- (BookmarkModel*)bookmarkModel {
+ return profile_->GetBookmarkModel();
+}
+
+// Maps a BookmarkNode to a table/outline row item placeholder.
+- (const BookmarkNode*)nodeFromItem:(id)item {
+ return (const BookmarkNode*)[item pointerValue];
+}
+
+// Maps a table/outline row item placeholder back to a BookmarkNode.
+- (id)itemFromNode:(const BookmarkNode*)node {
+ if (!nodeMap_) {
+ nodeMap_.reset([[NSMapTable alloc]
+ initWithKeyOptions:NSPointerFunctionsOpaqueMemory |
+ NSPointerFunctionsOpaquePersonality
+ valueOptions:NSPointerFunctionsStrongMemory
+ capacity:500]);
+ }
+ NSValue* item = (NSValue*)NSMapGet(nodeMap_, node);
+ if (!item) {
+ item = [NSValue valueWithPointer:node];
+ NSMapInsertKnownAbsent(nodeMap_, node, item);
+ }
+ return item;
+}
+
+// Removes a BookmarkNode from the node<->item mapping table.
+- (void)forgetNode:(const BookmarkNode*)node {
+ NSMapRemove(nodeMap_, node);
+ for (int i = node->GetChildCount() - 1 ; i >= 0 ; i--) {
+ [self forgetNode:node->GetChild(i)];
+ }
+}
+
+// Called when the bookmark model changes; forwards to the sub-controllers.
+- (void)nodeChanged:(const BookmarkNode*)node
+ childrenChanged:(BOOL)childrenChanged {
+ [groupsController_ nodeChanged:node childrenChanged:childrenChanged];
+ // TreeController only cares about nodes we have items for, so don't bother
+ // creating a new item if the node's never been seen:
+ id item = (NSValue*)NSMapGet(nodeMap_, node);
+ if (item) {
+ [treeController_ itemChanged:item childrenChanged:childrenChanged];
+ }
+}
+
+
+// Returns the icon (fav- or folder) for a table/outline item.
+- (NSImage*)iconForItem:(id)item {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ if (node->is_folder()) {
+ return folderIcon_;
+ } else if (node->is_url()) {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ const SkBitmap& skIcon = [self bookmarkModel]->GetFavIcon(node);
+ if (!skIcon.isNull()) {
+ return gfx::SkBitmapToNSImage(skIcon);
+ }
+ }
+ return defaultFavIcon_;
+}
+
+
+#pragma mark -
+#pragma mark WINDOW MANAGEMENT:
+
+
+// Public entry point to open the bookmark manager.
++ (BookmarkManagerController*)showBookmarkManager:(Profile*)profile
+{
+ if (!sInstance) {
+ sInstance = [[self alloc] initWithProfile:profile];
+ }
+ [sInstance showWindow:self];
+ return sInstance;
+}
+
+// When window closes, get rid of myself too. (NSWindow delegate)
+- (void)windowWillClose:(NSNotification*)n {
+ [self autorelease];
+}
+
+// Install the search field into the search toolbar item. (NSToolbar delegate)
+- (void)toolbarWillAddItem:(NSNotification*)notification {
+ NSToolbarItem* item = [[notification userInfo] objectForKey:@"item"];
+ if ([[item itemIdentifier] isEqualToString:@"search"]) {
+ [item setView:toolbarSearchView_];
+ NSSize size = [toolbarSearchView_ frame].size;
+ [item setMinSize:size];
+ [item setMaxSize:size];
+ }
+}
+
+// Called when the user types into the search field.
+- (IBAction)searchFieldChanged:(id)sender {
+ //TODO(snej): Implement this
+}
+
+
+// Open a bookmark, by having Chrome open a tab on its URL.
+- (void)openBookmarkItem:(id)item {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ DCHECK(node);
+ if (!node->is_url())
+ return;
+ GURL url = node->GetURL();
+
+ Browser* browser = BrowserList::GetLastActive();
+ // if no browser window exists then create one with no tabs to be filled in
+ if (!browser) {
+ browser = Browser::Create(profile_);
+ browser->window()->Show();
+ }
+ browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB,
+ PageTransition::AUTO_BOOKMARK);
+}
+
+@end
diff --git a/chrome/browser/cocoa/bookmark_manager_controller_unittest.mm b/chrome/browser/cocoa/bookmark_manager_controller_unittest.mm
new file mode 100644
index 0000000..8a3a00a
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_manager_controller_unittest.mm
@@ -0,0 +1,73 @@
+// 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/scoped_nsobject.h"
+#import "chrome/browser/cocoa/bookmark_manager_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"
+#include "testing/platform_test.h"
+
+namespace {
+
+class BookmarkManagerControllerTest : public CocoaTest {
+ public:
+ void SetUp() {
+ CocoaTest::SetUp();
+ controller_ = [BookmarkManagerController showBookmarkManager:
+ browser_test_helper_.profile()];
+ ASSERT_TRUE(controller_);
+ }
+
+ void TearDown() {
+ [controller_ close];
+ CocoaTest::TearDown();
+ }
+
+ BrowserTestHelper browser_test_helper_;
+ BookmarkManagerController* controller_;
+};
+
+TEST_F(BookmarkManagerControllerTest, IsThisThingTurnedOn) {
+ NSWindow* w = [controller_ window];
+ ASSERT_TRUE(w);
+ EXPECT_TRUE([w isVisible]);
+
+ ASSERT_TRUE([controller_ groupsController]);
+ ASSERT_TRUE([controller_ treeController]);
+}
+
+TEST_F(BookmarkManagerControllerTest, Model) {
+ BookmarkModel* model = [controller_ bookmarkModel];
+ ASSERT_EQ(browser_test_helper_.profile()->GetBookmarkModel(), model);
+
+ // Check the bookmarks-bar item:
+ const BookmarkNode* bar = model->GetBookmarkBarNode();
+ ASSERT_TRUE(bar);
+ id barItem = [controller_ itemFromNode:bar];
+ ASSERT_TRUE(barItem);
+
+ // Check the 'others' item:
+ const BookmarkNode* other = model->other_node();
+ ASSERT_TRUE(other);
+ EXPECT_NE(bar, other);
+ scoped_nsobject<id> otherItem([[controller_ itemFromNode:other] retain]);
+ ASSERT_TRUE(otherItem);
+
+ EXPECT_NE(barItem, otherItem);
+ EXPECT_FALSE([barItem isEqual:otherItem]);
+
+ EXPECT_EQ(bar, [controller_ nodeFromItem:barItem]);
+ EXPECT_EQ(barItem, [controller_ itemFromNode:bar]);
+ EXPECT_EQ(other, [controller_ nodeFromItem:otherItem]);
+ EXPECT_EQ(otherItem, [controller_ itemFromNode:other]);
+
+ // Now tell it to forget 'other' and see if we get a different item id:
+ [controller_ forgetNode:other];
+ id otherItem2 = [controller_ itemFromNode:other];
+ EXPECT_TRUE(otherItem2);
+ EXPECT_NE(otherItem, otherItem2);
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/bookmark_tree_controller.h b/chrome/browser/cocoa/bookmark_tree_controller.h
new file mode 100644
index 0000000..5e7b66e
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_tree_controller.h
@@ -0,0 +1,68 @@
+// 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 <vector>
+
+@class BookmarkManagerController;
+class BookmarkModel;
+class BookmarkNode;
+
+
+// Controller for the bookmark tree view (the right pane).
+@interface BookmarkTreeController : NSObject {
+ @private
+ IBOutlet NSOutlineView* outline_;
+ IBOutlet BookmarkManagerController* manager_;
+ id group_;
+ std::vector<const BookmarkNode*> draggedNodes_;
+}
+
+// The top-level bookmark folder used as the root of the outline's tree.
+// Observable, bindable.
+@property (assign) id group;
+// The currently selected item(s) in the outline. (Not observable.)
+@property (retain) NSArray* selectedItems;
+
+// Action for the Delete command; also invoked by the delete key.
+- (IBAction)delete:(id)sender;
+
+// Maps BookmarkNodes to NSOutlineView items. Equivalent to the method on
+// BookmarkManagerController except that it maps the root node to nil.
+- (id)itemFromNode:(const BookmarkNode*)node;
+
+// Maps NSOutlineView items back to BookmarkNodes. Equivalent to the method on
+// BookmarkManagerController except that it maps nil back to the root node.
+- (const BookmarkNode*)nodeFromItem:(id)item;
+
+// Called by the BookmarkManagerController to notify the data model's changed.
+- (void)itemChanged:(id)nodeItem childrenChanged:(BOOL)childrenChanged;
+
+@end
+
+
+// Drag/drop and copy/paste methods
+// (These are implemented in bookmark_tree_controller_paste.mm.)
+@interface BookmarkTreeController (Pasteboard)
+// One-time drag-n-drop setup; called from -awakeFromNib.
+- (void)registerDragTypes;
+- (IBAction)cut:(id)sender;
+- (IBAction)copy:(id)sender;
+- (IBAction)paste:(id)sender;
+@end
+
+
+// Exposed only for unit tests.
+@interface BookmarkTreeController (UnitTesting)
+
+- (BOOL)copyToPasteboard:(NSPasteboard*)pb;
+- (BOOL)pasteFromPasteboard:(NSPasteboard*)pb;
+@property (readonly) NSOutlineView* outline;
+
+@end
+
+
+// Outline view for bookmark tree; handles Cut/Copy/Paste and Delete key.
+@interface BookmarksOutlineView : NSOutlineView
+@end
diff --git a/chrome/browser/cocoa/bookmark_tree_controller.mm b/chrome/browser/cocoa/bookmark_tree_controller.mm
new file mode 100644
index 0000000..3de9d51
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_tree_controller.mm
@@ -0,0 +1,253 @@
+// 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 "chrome/browser/cocoa/bookmark_tree_controller.h"
+
+#include "base/nsimage_cache_mac.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/cocoa/bookmark_manager_controller.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "googleurl/src/gurl.h"
+#import "third_party/apple/ImageAndTextCell.h"
+
+
+@implementation BookmarkTreeController
+
+// Allow the |group| property to be bound (by BookmarkManagerController.)
++ (void)initialize {
+ [self exposeBinding:@"group"];
+}
+
+// Initialization after the nib is loaded.
+- (void)awakeFromNib {
+ [outline_ setTarget:self];
+ [outline_ setDoubleAction:@selector(itemDoubleClicked:)];
+ [self registerDragTypes];
+}
+
+- (id)group {
+ return group_;
+}
+
+- (void)setGroup:(id)group {
+ if (group != group_) {
+ group_ = group;
+
+ [outline_ deselectAll:self];
+ [outline_ reloadData];
+ [outline_ noteNumberOfRowsChanged];
+ }
+}
+
+- (NSOutlineView*)outline {
+ return outline_;
+}
+
+// Updates the tree after the data model has changed.
+- (void)itemChanged:(id)nodeItem childrenChanged:(BOOL)childrenChanged {
+ if (nodeItem == group_)
+ nodeItem = nil;
+ [outline_ reloadItem:nodeItem reloadChildren:childrenChanged];
+}
+
+// Getter for the |selectedItems| property.
+- (NSArray*)selectedItems {
+ NSMutableArray* items = [NSMutableArray array];
+ NSIndexSet* selectedRows = [outline_ selectedRowIndexes];
+ if (selectedRows != nil) {
+ for (NSInteger row = [selectedRows firstIndex]; row != NSNotFound;
+ row = [selectedRows indexGreaterThanIndex:row]) {
+ [items addObject:[outline_ itemAtRow:row]];
+ }
+ }
+ return items;
+}
+
+// Setter for the |selectedItems| property.
+- (void)setSelectedItems:(NSArray*)items {
+ NSMutableIndexSet* newSelection = [NSMutableIndexSet indexSet];
+
+ for (NSUInteger i = 0; i < [items count]; i++) {
+ NSInteger row = [outline_ rowForItem:[items objectAtIndex:i]];
+ if (row >= 0) {
+ [newSelection addIndex:row];
+ }
+ }
+
+ [outline_ selectRowIndexes:newSelection byExtendingSelection:NO];
+}
+
+
+#pragma mark -
+#pragma mark COMMANDS:
+
+
+// Responds to a double-click by opening the selected URL(s).
+- (IBAction)itemDoubleClicked:(id)sender {
+ for (id item in [self selectedItems]) {
+ [manager_ openBookmarkItem:item];
+ }
+}
+
+// The Delete command (also bound to the delete key.)
+- (IBAction)delete:(id)sender {
+ NSIndexSet* selectedRows = [outline_ selectedRowIndexes];
+ if (!selectedRows) {
+ NSBeep();
+ return;
+ }
+ // Iterate backwards so that any selected children are deleted before
+ // selected parents (opposite order would cause double-free!) and so each
+ // deletion doesn't invalidate the remaining row numbers.
+ for (NSInteger row = [selectedRows lastIndex]; row != NSNotFound;
+ row = [selectedRows indexLessThanIndex:row]) {
+ const BookmarkNode* node = [manager_ nodeFromItem:
+ [outline_ itemAtRow:row]];
+ const BookmarkNode* parent = node->GetParent();
+ [manager_ bookmarkModel]->Remove(parent, parent->IndexOfChild(node));
+ }
+
+ [outline_ reloadData];
+ [outline_ deselectAll:self];
+}
+
+
+#pragma mark -
+#pragma mark DATA SOURCE:
+
+
+// The NSOutlineView data source methods are called with a nil item to
+// represent the root of the tree; this compensates for that.
+- (const BookmarkNode*)nodeFromItem:(id)item {
+ return [manager_ nodeFromItem:(item ? item : group_)];
+}
+
+- (id)itemFromNode:(const BookmarkNode*)node {
+ id item = [manager_ itemFromNode:node];
+ return item == group_ ? nil : item;
+}
+
+// Returns the children of an item (NSOutlineView data source)
+- (NSArray*)childrenOfItem:(id)item {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ if (!node) {
+ return nil;
+ }
+ int nChildren = node->GetChildCount();
+ NSMutableArray* children = [NSMutableArray arrayWithCapacity:nChildren];
+ for (int i = 0; i < nChildren; i++) {
+ [children addObject:[self itemFromNode:node->GetChild(i)]];
+ }
+ return children;
+}
+
+// Returns the number of children of an item (NSOutlineView data source)
+- (NSInteger) outlineView:(NSOutlineView*)outlineView
+ numberOfChildrenOfItem:(id)item {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ return node ? node->GetChildCount() : 0;
+}
+
+// Returns a child of an item (NSOutlineView data source)
+- (id)outlineView:(NSOutlineView*)outlineView
+ child:(NSInteger)index
+ ofItem:(id)item {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ return [self itemFromNode:node->GetChild(index)];
+}
+
+// Returns whether an item is a folder (NSOutlineView data source)
+- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item {
+ return [self nodeFromItem:item]->is_folder();
+}
+
+// Returns the value to display in a cell (NSOutlineView data source)
+- (id) outlineView:(NSOutlineView*)outlineView
+ objectValueForTableColumn:(NSTableColumn*)tableColumn
+ byItem:(id)item {
+ const BookmarkNode* node = [self nodeFromItem:item];
+ NSString* ident = [tableColumn identifier];
+ if ([ident isEqualToString:@"title"]) {
+ return base::SysWideToNSString(node->GetTitle());
+ } else if ([ident isEqualToString:@"url"]) {
+ return base::SysUTF8ToNSString(node->GetURL().possibly_invalid_spec());
+ } else {
+ NOTREACHED();
+ return nil;
+ }
+}
+
+// Stores the edited value of a cell (NSOutlineView data source)
+- (void)outlineView:(NSOutlineView*)outlineView
+ setObjectValue:(id)value
+ forTableColumn:(NSTableColumn*)tableColumn
+ byItem:(id)item
+{
+ const BookmarkNode* node = [self nodeFromItem:item];
+ NSString* ident = [tableColumn identifier];
+ if ([ident isEqualToString:@"title"]) {
+ [manager_ bookmarkModel]->SetTitle(node, base::SysNSStringToWide(value));
+ } else if ([ident isEqualToString:@"url"]) {
+ GURL url(base::SysNSStringToUTF8(value));
+ if (url != node->GetURL()) {
+ //TODO(snej): Uncomment this once SetURL exists (bug 10603).
+ // ...or work around it by removing node and adding new one.
+ //[manager_ bookmarkModel]->SetURL(node, url);
+ }
+ }
+}
+
+// Returns whether a cell is editable (NSOutlineView data source)
+- (BOOL) outlineView:(NSOutlineView*)outlineView
+ shouldEditTableColumn:(NSTableColumn*)tableColumn
+ item:(id)item {
+ //TODO(snej): Make URL column editable once setter method exists (bug 10603).
+ NSString* ident = [tableColumn identifier];
+ return [ident isEqualToString:@"title"];
+}
+
+// Sets a cell's icon before it's drawn (NSOutlineView data source)
+- (void)outlineView:(NSOutlineView*)outlineView
+ willDisplayCell:(id)cell
+ forTableColumn:(NSTableColumn*)tableColumn
+ item:(id)item
+{
+ if ([[tableColumn identifier] isEqualToString:@"title"]) {
+ [(ImageAndTextCell*)cell setImage:[manager_ iconForItem:item]];
+ }
+}
+
+@end
+
+
+@implementation BookmarksOutlineView
+
+- (IBAction)cut:(id)sender {
+ [(BookmarkTreeController*)[self delegate] cut:sender];
+}
+
+- (IBAction)copy:(id)sender {
+ [(BookmarkTreeController*)[self delegate] copy:sender];
+}
+
+- (IBAction)paste:(id)sender {
+ [(BookmarkTreeController*)[self delegate] paste:sender];
+}
+
+- (IBAction)delete:(id)sender {
+ [(BookmarkTreeController*)[self delegate] delete:sender];
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ return [[self delegate] validateMenuItem:menuItem];
+}
+
+- (void)keyDown:(NSEvent*)event {
+ if ([event keyCode] == 51) // Delete key
+ [self delete:self];
+ else
+ [super keyDown:event];
+}
+
+@end
diff --git a/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm b/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm
new file mode 100644
index 0000000..e617b4c
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_tree_controller_pasteboard.mm
@@ -0,0 +1,439 @@
+// 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 "chrome/browser/cocoa/bookmark_tree_controller.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#import "chrome/browser/cocoa/bookmark_manager_controller.h"
+#include "googleurl/src/gurl.h"
+
+
+// Safari uses this type, though it's not declared in any header.
+static NSString* const BookmarkDictionaryListPboardType =
+ @"BookmarkDictionaryListPboardType";
+
+// Mac WebKit uses this type, declared in WebKit/mac/History/WebURLsWithTitles.h
+static NSString* const WebURLsWithTitlesPboardType =
+ @"WebURLsWithTitlesPboardType";
+
+// Used internally to identify intra-outline drags.
+static NSString* const kCustomPboardType =
+ @"ChromeBookmarkTreeControllerPlaceholderType";
+
+
+@implementation BookmarkTreeController (Pasteboard)
+
+
+// One-time dnd setup; called from -awakeFromNib.
+- (void)registerDragTypes {
+ [outline_ registerForDraggedTypes:[NSArray arrayWithObjects:
+ BookmarkDictionaryListPboardType,
+ WebURLsWithTitlesPboardType,
+ NSURLPboardType, nil]];
+ [outline_ setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
+ [outline_ setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
+}
+
+// Selects a range of items in a parent node.
+- (void)selectNodesInFolder:(const BookmarkNode*)parent
+ atIndexes:(NSRange)childRange {
+ DCHECK(NSMaxRange(childRange) <= (NSUInteger)parent->GetChildCount());
+ id parentItem = [self itemFromNode:parent];
+ if (parentItem != nil) {
+ // If parent is not the root, need to offset range by parent's index:
+ int startRow = [outline_ rowForItem:parentItem];
+ if (startRow < 0) {
+ return;
+ }
+ if ([outline_ isItemExpanded:parentItem]) {
+ childRange.location += startRow + 1;
+ } else {
+ childRange.location = startRow;
+ childRange.length = 1;
+ }
+ }
+ NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange:childRange];
+ [outline_ selectRowIndexes:indexes byExtendingSelection:NO];
+}
+
+
+#pragma mark -
+#pragma mark DRAGGING OUT AND COPYING:
+
+
+// Generates parallel arrays of URLs and titles for contents of a node.
+static void flattenNode(const BookmarkNode* node,
+ NSMutableArray* urlStrings,
+ NSMutableArray* titles) {
+ if (node->is_folder()) {
+ for (int i = 0; i < node->GetChildCount(); i++) {
+ flattenNode(node->GetChild(i), urlStrings, titles);
+ }
+ } else if (node->is_url()) {
+ [urlStrings addObject:base::SysUTF8ToNSString(
+ node->GetURL().possibly_invalid_spec())];
+ [titles addObject:base::SysWideToNSString(node->GetTitle())];
+ }
+}
+
+// Writes data to the pasteboard given a list of row items.
+- (BOOL)writeItems:(NSArray*)items
+ toPasteboard:(NSPasteboard*)pb
+ includeCustom:(BOOL)includeCustom {
+ if ([items count] == 0) {
+ return NO;
+ }
+
+ [pb declareTypes:[NSMutableArray arrayWithObjects:
+ WebURLsWithTitlesPboardType,
+ NSStringPboardType, nil]
+ owner:self];
+
+ // Add URLs and titles:
+ NSMutableArray* urls = [NSMutableArray array];
+ NSMutableArray* titles = [NSMutableArray array];
+ for (id item in items) {
+ flattenNode([self nodeFromItem:item], urls, titles);
+ }
+ [pb setPropertyList:[NSArray arrayWithObjects:urls, titles, nil]
+ forType:WebURLsWithTitlesPboardType];
+
+ // Add plain text, as one URL per line:
+ [pb setString:[urls componentsJoinedByString:@"\n"]
+ forType:NSStringPboardType];
+
+ // Add custom type. The actual data doesn't matter since kCustomPboardType
+ // drags aren't recognized by anyone but us.
+ if (includeCustom) {
+ draggedNodes_.clear();
+ for (id item in items) {
+ draggedNodes_.push_back([self nodeFromItem:item]);
+ }
+ [pb addTypes:[NSArray arrayWithObject: kCustomPboardType] owner: self];
+ [pb setData:[NSData data] forType:kCustomPboardType];
+ }
+
+ // Add single URL:
+ if ([urls count] == 1) {
+ [pb addTypes:[NSArray arrayWithObject: NSURLPboardType] owner: self];
+ NSString* firstURLStr = [urls objectAtIndex:0];
+ [pb setString:firstURLStr forType:NSURLPboardType];
+ }
+ return YES;
+}
+
+// Invoked when dragging outline-view rows.
+- (BOOL)outlineView:(NSOutlineView*)outlineView
+ writeItems:(NSArray*)items
+ toPasteboard:(NSPasteboard*)pb {
+ [self writeItems:items toPasteboard:pb includeCustom:YES];
+ return YES;
+}
+
+
+// The Cut command.
+- (IBAction)cut:(id)sender {
+ if ([self writeItems:[self selectedItems]
+ toPasteboard:[NSPasteboard generalPasteboard]
+ includeCustom:NO]) {
+ [self delete:self];
+ } else {
+ NSBeep();
+ }
+}
+
+// The Copy command.
+- (IBAction)copy:(id)sender {
+ if (![self copyToPasteboard:[NSPasteboard generalPasteboard]])
+ NSBeep();
+}
+
+// Copy to any pasteboard.
+- (BOOL)copyToPasteboard:(NSPasteboard*)pb {
+ return [self writeItems:[self selectedItems]
+ toPasteboard:pb
+ includeCustom:NO];
+}
+
+
+#pragma mark -
+#pragma mark INCOMING DRAGS AND PASTING:
+
+
+// BookmarkDictionaryListPboardType represents bookmarks as dictionaries,
+// which have the following keys.
+// Strangely, folder nodes (whose WebBookmarkType is WebBookmarkTypeLeaf) have
+// their title under 'Title', while leaf nodes have it in 'URIDictionary.title'.
+static const NSString* kTitleKey = @"Title";
+static const NSString* kURIDictionaryKey = @"URIDictionary";
+static const NSString* kURIDictTitleKey = @"title";
+static const NSString* kURLStringKey = @"URLString";
+static const NSString* kTypeKey = @"WebBookmarkType";
+static const NSString* kLeafType = @"WebBookmarkTypeLeaf";
+//static const NSString* kListType = @"WebBookmarkTypeList"; // unused for now
+static const NSString* kChildrenKey = @"Children";
+
+// Helper that creates a dictionary in BookmarkDictionaryListPboardType format.
+// |name| may be nil, but |urlStr| is required.
+static NSDictionary* makeBookmarkPlistEntry(NSString* name, NSString* urlStr) {
+ if (!name) {
+ name = urlStr;
+ }
+ NSDictionary* nameDict = [NSDictionary dictionaryWithObject:name
+ forKey:kURIDictTitleKey];
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ kLeafType, kTypeKey,
+ nameDict, kURIDictionaryKey,
+ urlStr, kURLStringKey,
+ nil];
+}
+
+// Reads URL(s) off the pasteboard and returns them in BookmarkDictionaryList-
+// PboardType format, or nil on failure.
+- (NSArray*)readPropertyListFromPasteboard:(NSPasteboard*)pb {
+ NSString* type = [pb availableTypeFromArray:
+ [outline_ registeredDraggedTypes]];
+ if ([type isEqualToString:BookmarkDictionaryListPboardType]) {
+ // Safari's full bookmark plist type:
+ return [pb propertyListForType:type];
+
+ } else if ([type isEqualToString:WebURLsWithTitlesPboardType]) {
+ // Safari's parallel-URLs-and-titles type:
+ NSArray* contents = [pb propertyListForType:type];
+ NSArray* urlStrings = [contents objectAtIndex:0];
+ NSArray* titles = [contents objectAtIndex:1];
+ NSUInteger n = [urlStrings count];
+ if (n == 0 || [titles count] != n) {
+ return nil;
+ }
+ NSMutableArray* plist = [NSMutableArray array];
+ for (NSUInteger i = 0; i < n; i++) {
+ [plist addObject:makeBookmarkPlistEntry([titles objectAtIndex:i],
+ [urlStrings objectAtIndex:i])];
+ }
+ return plist;
+
+ } else if ([type isEqualToString:NSURLPboardType]) {
+ // Standard URL type:
+ NSString* urlStr = [[NSURL URLFromPasteboard:pb] absoluteString];
+ if (!urlStr) {
+ return nil;
+ }
+ NSString* title = [pb stringForType:@"public.url-name"];
+ if (!title)
+ title = [pb stringForType:NSStringPboardType];
+ return [NSArray arrayWithObject:makeBookmarkPlistEntry(title, urlStr)];
+
+ } else {
+ return nil;
+ }
+}
+
+
+// Moves BookmarkNodes into a parent folder, then selects them.
+- (void)moveNodes:(std::vector<const BookmarkNode*>)nodes
+ toFolder:(const BookmarkNode*)dstParent
+ atIndex:(int)dstIndex {
+ for (std::vector<const BookmarkNode*>::iterator it = nodes.begin();
+ it != nodes.end(); ++it) {
+ // Use an autorelease pool to clean up after the various observers that
+ // get called after each individual bookmark change.
+ NSAutoreleasePool* pool = [NSAutoreleasePool new];
+ const BookmarkNode* srcNode = *it;
+ const BookmarkNode* srcParent = srcNode->GetParent();
+ int srcIndex = srcParent->IndexOfChild(srcNode);
+ [manager_ bookmarkModel]->Move(srcNode, dstParent, dstIndex);
+ if (srcParent != dstParent || srcIndex >= dstIndex) {
+ dstIndex++;
+ }
+ [pool drain];
+ }
+
+ [self selectNodesInFolder:dstParent
+ atIndexes:NSMakeRange(dstIndex - nodes.size(), nodes.size())];
+}
+
+// Inserts bookmarks in BookmarkDictionaryListPboardType into a folder node.
+- (void)insertPropertyList:(NSArray*)plist
+ inFolder:(const BookmarkNode*)dstParent
+ atIndex:(NSInteger)dstIndex {
+ BookmarkModel* model = [manager_ bookmarkModel];
+ NSInteger i = 0;
+ for (NSDictionary* plistItem in plist) {
+ // Use an autorelease pool to clean up after the various observers that
+ // get called after each individual bookmark change.
+ NSAutoreleasePool* pool = [NSAutoreleasePool new];
+ if ([[plistItem objectForKey:kTypeKey] isEqual:kLeafType]) {
+ NSString* title = [[plistItem objectForKey:kURIDictionaryKey]
+ objectForKey:kURIDictTitleKey];
+ NSString* urlStr = [plistItem objectForKey:kURLStringKey];
+ if (title && urlStr) {
+ model->AddURL(dstParent,
+ dstIndex + i,
+ base::SysNSStringToWide(title),
+ GURL(base::SysNSStringToUTF8(urlStr)));
+ ++i;
+ }
+ } else {
+ NSString* title = [plistItem objectForKey:kTitleKey];
+ NSArray* children = [plistItem objectForKey:kChildrenKey];
+ if (title && children) {
+ const BookmarkNode* newFolder;
+ newFolder = model->AddGroup(dstParent,
+ dstIndex + i,
+ base::SysNSStringToWide(title));
+ ++i;
+ [self insertPropertyList:children
+ inFolder:newFolder
+ atIndex:0];
+ }
+ }
+ [pool drain];
+ }
+ [self selectNodesInFolder:dstParent
+ atIndexes:NSMakeRange(dstIndex, [plist count])];
+}
+
+
+// Validates whether or not the proposed drop is valid.
+- (NSDragOperation)outlineView:(NSOutlineView*)outlineView
+ validateDrop:(id <NSDraggingInfo>)info
+ proposedItem:(id)item
+ proposedChildIndex:(NSInteger)childIndex {
+ NSPasteboard* pb = [info draggingPasteboard];
+
+ // Check to see what we are proposed to be dropping on
+ const BookmarkNode*targetNode = [self nodeFromItem:item];
+ if (!targetNode->is_folder()) {
+ // The target node is not a container, but a leaf.
+ // Refuse the drop (we may get called again with a between)
+ if (childIndex == NSOutlineViewDropOnItemIndex) {
+ return NSDragOperationNone;
+ }
+ }
+
+ // Dragging within the outline?
+ if ([info draggingSource] == outlineView &&
+ [[pb types] containsObject:kCustomPboardType]) {
+ // If we are allowing the drop, we see if we are dragging from ourselves
+ // and dropping into a descendent, which wouldn't be allowed...
+ // See if the appropriate drag information is available on the pasteboard.
+ //TODO(snej): Re-implement this
+ /*
+ if (targetNode != group_ &&
+ [[[info draggingPasteboard] types] containsObject:kCustomPboardType]) {
+ for (NSDictionary* draggedNode in draggedNodes_) {
+ if ([self treeNode:targetNode isDescendantOfNode:draggedNode]) {
+ // Yup, it is, refuse it.
+ return NSDragOperationNone;
+ break;
+ }
+ }
+ */
+ return NSDragOperationMove;
+ }
+
+ // Drag from elsewhere is a copy.
+ return NSDragOperationCopy;
+}
+
+// Actually handles the drop.
+- (BOOL)outlineView:(NSOutlineView*)outlineView
+ acceptDrop:(id <NSDraggingInfo>)info
+ item:(id)item
+ childIndex:(NSInteger)childIndex
+{
+ NSPasteboard* pb = [info draggingPasteboard];
+
+ const BookmarkNode* targetNode = [self nodeFromItem:item];
+
+ // Determine the parent to insert into and the child index to insert at.
+ if (!targetNode->is_folder()) {
+ // If our target is a leaf, and we are dropping on it.
+ if (childIndex == NSOutlineViewDropOnItemIndex) {
+ return NO;
+ } else {
+ // We will be dropping on the item's parent at the target index
+ // of this child, plus one.
+ const BookmarkNode* oldTargetNode = targetNode;
+ targetNode = targetNode->GetParent();
+ childIndex = targetNode->IndexOfChild(oldTargetNode) + 1;
+ }
+ } else {
+ if (childIndex == NSOutlineViewDropOnItemIndex) {
+ // Insert it at the end, if we were dropping on it
+ childIndex = targetNode->GetChildCount();
+ }
+ }
+
+ if ([info draggingSource] == outlineView &&
+ [[pb types] containsObject:kCustomPboardType]) {
+ // If the source was ourselves, move the selected nodes.
+ [self moveNodes:draggedNodes_
+ toFolder:targetNode
+ atIndex:childIndex];
+ } else {
+ NSArray* plist = [self readPropertyListFromPasteboard:pb];
+ if (!plist) {
+ return NO;
+ }
+ [self insertPropertyList:plist
+ inFolder:targetNode
+ atIndex:childIndex];
+ }
+ return YES;
+}
+
+
+// The Paste command.
+- (IBAction)paste:(id)sender {
+ if (![self pasteFromPasteboard:[NSPasteboard generalPasteboard]])
+ NSBeep();
+}
+
+- (BOOL)pasteFromPasteboard:(NSPasteboard*)pb {
+ NSArray* plist = [self readPropertyListFromPasteboard: pb];
+ if (!plist)
+ return NO;
+
+ const BookmarkNode* targetNode;
+ NSInteger childIndex;
+ int selRow = [outline_ selectedRow];
+ if (selRow >= 0) {
+ // Insert after selected row.
+ const BookmarkNode* selNode = [self nodeFromItem:
+ [outline_ itemAtRow:selRow]];
+ targetNode = selNode->GetParent();
+ childIndex = targetNode->IndexOfChild(selNode) + 1;
+ } else {
+ // ...or at very end if there's no selection:
+ targetNode = [self nodeFromItem:group_];
+ childIndex = targetNode->GetChildCount();
+ }
+
+ [self insertPropertyList:plist
+ inFolder:targetNode
+ atIndex:childIndex];
+ return YES;
+}
+
+
+// Selectively enables/disables menu commands.
+- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
+ SEL action = [menuItem action];
+ if (action == @selector(cut:) || action == @selector(copy:) ||
+ action == @selector(delete:)) {
+ return [[outline_ selectedRowIndexes] count] > 0;
+ } else if (action == @selector(paste:)) {
+ return [[NSPasteboard generalPasteboard]
+ availableTypeFromArray:[outline_ registeredDraggedTypes]]
+ != nil;
+ } else {
+ return YES;
+ }
+}
+
+
+@end
diff --git a/chrome/browser/cocoa/bookmark_tree_controller_unittest.mm b/chrome/browser/cocoa/bookmark_tree_controller_unittest.mm
new file mode 100644
index 0000000..dc22f19
--- /dev/null
+++ b/chrome/browser/cocoa/bookmark_tree_controller_unittest.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/scoped_nsobject.h"
+#import "chrome/browser/cocoa/bookmark_groups_controller.h"
+#import "chrome/browser/cocoa/bookmark_manager_controller.h"
+#import "chrome/browser/cocoa/bookmark_tree_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"
+#include "testing/platform_test.h"
+
+// Mac WebKit uses this type, declared in WebKit/mac/History/WebURLsWithTitles.h
+static NSString* const WebURLsWithTitlesPboardType =
+ @"WebURLsWithTitlesPboardType";
+
+namespace {
+
+class BookmarkTreeControllerTest : public CocoaTest {
+ public:
+ void SetUp() {
+ CocoaTest::SetUp();
+ pasteboard_ = [NSPasteboard pasteboardWithUniqueName];
+ manager_ = [BookmarkManagerController showBookmarkManager:
+ browser_test_helper_.profile()];
+ ASSERT_TRUE(manager_);
+ treeController_ = [manager_ treeController];
+ ASSERT_TRUE(treeController_);
+ }
+
+ void TearDown() {
+ [manager_ close];
+ [pasteboard_ releaseGlobally];
+ CocoaTest::TearDown();
+ }
+
+ id SelectBar() {
+ BookmarkModel* model = [manager_ bookmarkModel];
+ id barItem = [manager_ itemFromNode:model->GetBookmarkBarNode()];
+ [[manager_ groupsController] setSelectedGroup:barItem];
+ return barItem;
+ }
+
+ id AddToBar(const std::wstring& title, const std::string& urlStr) {
+ BookmarkModel* model = [manager_ bookmarkModel];
+ const BookmarkNode* bar = model->GetBookmarkBarNode();
+ const BookmarkNode* node;
+ node = model->AddURL(bar, bar->GetChildCount(), title, GURL(urlStr));
+ return [manager_ itemFromNode:node];
+ }
+
+ BrowserTestHelper browser_test_helper_;
+ BookmarkManagerController* manager_;
+ BookmarkTreeController* treeController_;
+ NSPasteboard* pasteboard_;
+};
+
+TEST_F(BookmarkTreeControllerTest, Model) {
+ // Select nothing in the group list and check tree is empty:
+ BookmarkGroupsController* groupsController = [manager_ groupsController];
+ [groupsController setSelectedGroup:nil];
+ ASSERT_EQ(nil, [treeController_ group]);
+
+ // Select the bookmarks bar and check that it's shown in the tree:
+ id barItem = SelectBar();
+ ASSERT_EQ(barItem, [treeController_ group]);
+}
+
+TEST_F(BookmarkTreeControllerTest, Selection) {
+ SelectBar();
+ id test1 = AddToBar(L"Test 1", "http://example.com/test1");
+ id test2 = AddToBar(L"Test 2", "http://example.com/test2");
+ id test3 = AddToBar(L"Test 3", "http://example.com/test3");
+ EXPECT_EQ(0U, [[treeController_ selectedItems] count]);
+
+ NSArray* sel = [NSArray arrayWithObject:test2];
+ [treeController_ setSelectedItems:sel];
+ EXPECT_TRUE([sel isEqual:[treeController_ selectedItems]]);
+ sel = [NSArray arrayWithObjects:test1, test3, nil];
+ [treeController_ setSelectedItems:sel];
+ EXPECT_TRUE([sel isEqual:[treeController_ selectedItems]]);
+ sel = [NSArray arrayWithObjects:test1, test2, test3, nil];
+ [treeController_ setSelectedItems:sel];
+ EXPECT_TRUE([sel isEqual:[treeController_ selectedItems]]);
+ sel = [NSArray array];
+ [treeController_ setSelectedItems:sel];
+ EXPECT_TRUE([sel isEqual:[treeController_ selectedItems]]);
+}
+
+TEST_F(BookmarkTreeControllerTest, CopyURLs) {
+ SelectBar();
+ AddToBar(L"Test 1", "http://example.com/test1");
+ AddToBar(L"Test 2", "http://example.com/test2");
+ AddToBar(L"Test 3", "http://example.com/test3");
+ [[treeController_ outline] selectAll:treeController_];
+
+ ASSERT_TRUE([treeController_ copyToPasteboard:pasteboard_]);
+
+ NSArray* contents = [pasteboard_ propertyListForType:
+ WebURLsWithTitlesPboardType];
+ ASSERT_TRUE([contents isKindOfClass:[NSArray class]]);
+ NSArray* urlStrings = [contents objectAtIndex:0];
+ EXPECT_TRUE([urlStrings isKindOfClass:[NSArray class]]);
+ NSArray* expectedURLStrings = [NSArray arrayWithObjects:
+ @"http://example.com/test1",
+ @"http://example.com/test2",
+ @"http://example.com/test3", nil];
+ EXPECT_TRUE([urlStrings isEqual:expectedURLStrings]);
+ NSArray* titles = [contents objectAtIndex:1];
+ EXPECT_TRUE([titles isKindOfClass:[NSArray class]]);
+ NSArray* expectedTitles = [NSArray arrayWithObjects:
+ @"Test 1",
+ @"Test 2",
+ @"Test 3", nil];
+ EXPECT_TRUE([titles isEqual:expectedTitles]);
+
+ NSString* str = [pasteboard_ stringForType:NSStringPboardType];
+ EXPECT_TRUE([str isEqual:
+ @"http://example.com/test1\n"
+ "http://example.com/test2\n"
+ "http://example.com/test3"]);
+
+ EXPECT_FALSE([pasteboard_ dataForType:NSURLPboardType]);
+}
+
+TEST_F(BookmarkTreeControllerTest, PasteSingleURL) {
+ [pasteboard_ declareTypes:[NSArray arrayWithObjects:
+ NSURLPboardType, @"public.url-name", nil]
+ owner:nil];
+ [[NSURL URLWithString:@"http://google.com"] writeToPasteboard:pasteboard_];
+ [pasteboard_ setString:@"Gooooogle" forType:@"public.url-name"];
+
+ SelectBar();
+ AddToBar(L"Test 1", "http://example.com/test1");
+ AddToBar(L"Test 2", "http://example.com/test2");
+ AddToBar(L"Test 3", "http://example.com/test3");
+
+ ASSERT_TRUE([treeController_ pasteFromPasteboard:pasteboard_]);
+ EXPECT_EQ(4, [[treeController_ outline] numberOfRows]);
+ EXPECT_EQ(3, [[treeController_ outline] selectedRow]);
+ NSArray* sel = [treeController_ selectedItems];
+ ASSERT_EQ(1U, [sel count]);
+ const BookmarkNode* node = [manager_ nodeFromItem:[sel objectAtIndex:0]];
+ ASSERT_TRUE(node);
+ EXPECT_EQ(GURL("http://google.com"), node->GetURL());
+ EXPECT_EQ(L"Gooooogle", node->GetTitle());
+}
+
+TEST_F(BookmarkTreeControllerTest, PasteMultipleURLs) {
+ [pasteboard_ declareTypes:[NSArray arrayWithObjects:
+ WebURLsWithTitlesPboardType,
+ NSURLPboardType, nil]
+ owner:nil];
+ NSMutableArray* urls = [NSArray arrayWithObjects:
+ @"http://google.com", @"http://chromium.org", nil];
+ NSMutableArray* titles = [NSArray arrayWithObjects:
+ @"Gooooogle", @"Chrooooomium", nil];
+ [pasteboard_ setPropertyList:[NSArray arrayWithObjects:urls, titles, nil]
+ forType:WebURLsWithTitlesPboardType];
+ [[NSURL URLWithString:@"http://example.com"] writeToPasteboard:pasteboard_];
+
+ SelectBar();
+ AddToBar(L"Test 1", "http://example.com/test1");
+ id test2 = AddToBar(L"Test 2", "http://example.com/test2");
+ AddToBar(L"Test 3", "http://example.com/test3");
+ [treeController_ setSelectedItems:[NSArray arrayWithObject:test2]];
+
+ ASSERT_TRUE([treeController_ pasteFromPasteboard:pasteboard_]);
+ EXPECT_EQ(5, [[treeController_ outline] numberOfRows]);
+ EXPECT_TRUE([[[treeController_ outline] selectedRowIndexes]
+ isEqual:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 2)]]);
+ NSArray* sel = [treeController_ selectedItems];
+ ASSERT_EQ(2U, [sel count]);
+
+ const BookmarkNode* node = [manager_ nodeFromItem:[sel objectAtIndex:0]];
+ ASSERT_TRUE(node);
+ EXPECT_EQ(GURL("http://google.com"), node->GetURL());
+ EXPECT_EQ(L"Gooooogle", node->GetTitle());
+ node = [manager_ nodeFromItem:[sel objectAtIndex:1]];
+ ASSERT_TRUE(node);
+ EXPECT_EQ(GURL("http://chromium.org"), node->GetURL());
+ EXPECT_EQ(L"Chrooooomium", node->GetTitle());
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm
index a7e5bf1..c25a32e 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/cocoa/browser_window_cocoa.mm
@@ -10,6 +10,7 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_list.h"
+#import "chrome/browser/cocoa/bookmark_manager_controller.h"
#include "chrome/browser/cocoa/browser_window_cocoa.h"
#import "chrome/browser/cocoa/browser_window_controller.h"
#import "chrome/browser/cocoa/bug_report_window_controller.h"
@@ -253,7 +254,7 @@ void BrowserWindowCocoa::ShowTaskManager() {
}
void BrowserWindowCocoa::ShowBookmarkManager() {
- NOTIMPLEMENTED();
+ [BookmarkManagerController showBookmarkManager:browser_->profile()];
}
void BrowserWindowCocoa::ShowBookmarkBubble(const GURL& url,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 65ca6b9..9ee667f 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -349,6 +349,10 @@
'browser/cocoa/bookmark_editor_base_controller.mm',
'browser/cocoa/bookmark_editor_controller.h',
'browser/cocoa/bookmark_editor_controller.mm',
+ 'browser/cocoa/bookmark_groups_controller.mm',
+ 'browser/cocoa/bookmark_groups_controller.h',
+ 'browser/cocoa/bookmark_manager_controller.h',
+ 'browser/cocoa/bookmark_manager_controller.mm',
'browser/cocoa/bookmark_menu.h',
'browser/cocoa/bookmark_menu.mm',
'browser/cocoa/bookmark_menu_bridge.h',
@@ -357,6 +361,9 @@
'browser/cocoa/bookmark_menu_cocoa_controller.mm',
'browser/cocoa/bookmark_name_folder_controller.h',
'browser/cocoa/bookmark_name_folder_controller.mm',
+ 'browser/cocoa/bookmark_tree_controller.h',
+ 'browser/cocoa/bookmark_tree_controller.mm',
+ 'browser/cocoa/bookmark_tree_controller_pasteboard.mm',
'browser/cocoa/bookmark_tree_browser_cell.h',
'browser/cocoa/bookmark_tree_browser_cell.mm',
'browser/cocoa/browser_command_executor.h',
@@ -2010,6 +2017,7 @@
'app/nibs/BookmarkBar.xib',
'app/nibs/BookmarkBubble.xib',
'app/nibs/BookmarkEditor.xib',
+ 'app/nibs/BookmarkManager.xib',
'app/nibs/BookmarkNameFolder.xib',
'app/nibs/ClearBrowsingData.xib',
'app/nibs/DownloadItem.xib',
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index b3d4d38f..29edb9e 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -183,6 +183,7 @@
'app/nibs/BookmarkBar.xib',
'app/nibs/BookmarkBubble.xib',
'app/nibs/BookmarkEditor.xib',
+ 'app/nibs/BookmarkManager.xib',
'app/nibs/BookmarkNameFolder.xib',
'app/nibs/BrowserWindow.xib',
'app/nibs/ClearBrowsingData.xib',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 6e4673c..829be9e 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -575,11 +575,14 @@
'browser/cocoa/bookmark_button_cell_unittest.mm',
'browser/cocoa/bookmark_editor_base_controller_unittest.mm',
'browser/cocoa/bookmark_editor_controller_unittest.mm',
+ 'browser/cocoa/bookmark_groups_controller_unittest.mm',
+ 'browser/cocoa/bookmark_manager_controller_unittest.mm',
'browser/cocoa/bookmark_menu_unittest.mm',
'browser/cocoa/bookmark_menu_bridge_unittest.mm',
'browser/cocoa/bookmark_menu_cocoa_controller_unittest.mm',
'browser/cocoa/bookmark_name_folder_controller_unittest.mm',
'browser/cocoa/bookmark_tree_browser_cell_unittest.mm',
+ 'browser/cocoa/bookmark_tree_controller_unittest.mm',
'browser/cocoa/browser_frame_view_unittest.mm',
'browser/cocoa/browser_window_cocoa_unittest.mm',
'browser/cocoa/browser_window_controller_unittest.mm',