Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h" |
| 6 | 6 |
| 7 #include "base/mac/bundle_locations.h" | 7 #include "base/mac/bundle_locations.h" |
| 8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
| 9 #include "chrome/browser/ui/bookmarks/bookmark_bubble_observer.h" | |
| 9 #include "chrome/browser/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
| 10 #include "chrome/browser/ui/browser_finder.h" | 11 #include "chrome/browser/ui/browser_finder.h" |
| 11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" | 12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" |
| 12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h" | 13 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_sync_promo_controller.h" |
| 13 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 14 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| 14 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | 15 #import "chrome/browser/ui/cocoa/info_bubble_view.h" |
| 15 #include "chrome/browser/ui/sync/sync_promo_ui.h" | 16 #include "chrome/browser/ui/sync/sync_promo_ui.h" |
| 16 #include "chrome/grit/generated_resources.h" | 17 #include "chrome/grit/generated_resources.h" |
| 17 #include "components/bookmarks/browser/bookmark_model.h" | 18 #include "components/bookmarks/browser/bookmark_model.h" |
| 18 #include "components/bookmarks/browser/bookmark_utils.h" | 19 #include "components/bookmarks/browser/bookmark_utils.h" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 47 // Singleton object to act as a representedObject for the "choose another | 48 // Singleton object to act as a representedObject for the "choose another |
| 48 // folder" item in the pop up. | 49 // folder" item in the pop up. |
| 49 static ChooseAnotherFolder* object = nil; | 50 static ChooseAnotherFolder* object = nil; |
| 50 if (!object) { | 51 if (!object) { |
| 51 object = [[ChooseAnotherFolder alloc] init]; | 52 object = [[ChooseAnotherFolder alloc] init]; |
| 52 } | 53 } |
| 53 return object; | 54 return object; |
| 54 } | 55 } |
| 55 | 56 |
| 56 - (id)initWithParentWindow:(NSWindow*)parentWindow | 57 - (id)initWithParentWindow:(NSWindow*)parentWindow |
| 58 observer:(bookmarks::BookmarkBubbleObserver*)observer | |
| 57 managed:(bookmarks::ManagedBookmarkService*)managed | 59 managed:(bookmarks::ManagedBookmarkService*)managed |
| 58 model:(BookmarkModel*)model | 60 model:(BookmarkModel*)model |
| 59 node:(const BookmarkNode*)node | 61 node:(const BookmarkNode*)node |
| 60 alreadyBookmarked:(BOOL)alreadyBookmarked { | 62 alreadyBookmarked:(BOOL)alreadyBookmarked { |
| 61 DCHECK(managed); | 63 DCHECK(managed); |
| 62 DCHECK(node); | 64 DCHECK(node); |
| 63 if ((self = [super initWithWindowNibPath:@"BookmarkBubble" | 65 if ((self = [super initWithWindowNibPath:@"BookmarkBubble" |
| 64 parentWindow:parentWindow | 66 parentWindow:parentWindow |
| 65 anchoredAt:NSZeroPoint])) { | 67 anchoredAt:NSZeroPoint])) { |
| 68 bookmarkBubbleObserver_ = observer; | |
| 66 managedBookmarkService_ = managed; | 69 managedBookmarkService_ = managed; |
| 67 model_ = model; | 70 model_ = model; |
| 68 node_ = node; | 71 node_ = node; |
| 69 alreadyBookmarked_ = alreadyBookmarked; | 72 alreadyBookmarked_ = alreadyBookmarked; |
| 70 } | 73 } |
| 71 return self; | 74 return self; |
| 72 } | 75 } |
| 73 | 76 |
| 74 - (void)awakeFromNib { | 77 - (void)awakeFromNib { |
| 75 [super awakeFromNib]; | 78 [super awakeFromNib]; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 94 // Adjust the height of the bubble so that the sync promo fits in it, | 97 // Adjust the height of the bubble so that the sync promo fits in it, |
| 95 // except for its bottom border. The xib file hides the left and right | 98 // except for its bottom border. The xib file hides the left and right |
| 96 // borders of the sync promo. | 99 // borders of the sync promo. |
| 97 NSRect bubbleFrame = [[self window] frame]; | 100 NSRect bubbleFrame = [[self window] frame]; |
| 98 bubbleFrame.size.height += | 101 bubbleFrame.size.height += |
| 99 syncPromoHeight - [syncPromoController_ borderWidth]; | 102 syncPromoHeight - [syncPromoController_ borderWidth]; |
| 100 [[self window] setFrame:bubbleFrame display:YES]; | 103 [[self window] setFrame:bubbleFrame display:YES]; |
| 101 } | 104 } |
| 102 } | 105 } |
| 103 | 106 |
| 104 // If this is a new bookmark somewhere visible (e.g. on the bookmark | 107 - (void)notifyBubbleClosed { |
| 105 // bar), pulse it. Else, call ourself recursively with our parent | 108 if (!bookmarkBubbleObserver_) |
| 106 // until we find something visible to pulse. | 109 return; |
| 107 - (void)startPulsingBookmarkButton:(const BookmarkNode*)node { | |
| 108 while (node) { | |
| 109 if ((node->parent() == model_->bookmark_bar_node()) || | |
| 110 (node->parent() == | |
| 111 managedBookmarkService_->managed_node()) || | |
| 112 (node->parent() == managedBookmarkService_->supervised_node()) || | |
| 113 (node == model_->other_node())) { | |
| 114 pulsingBookmarkNode_ = node; | |
| 115 bookmarkObserver_->StartObservingNode(pulsingBookmarkNode_); | |
| 116 NSValue *value = [NSValue valueWithPointer:node]; | |
| 117 NSDictionary *dict = [NSDictionary | |
| 118 dictionaryWithObjectsAndKeys:value, | |
| 119 bookmark_button::kBookmarkKey, | |
| 120 [NSNumber numberWithBool:YES], | |
| 121 bookmark_button::kBookmarkPulseFlagKey, | |
| 122 nil]; | |
| 123 [[NSNotificationCenter defaultCenter] | |
| 124 postNotificationName:bookmark_button::kPulseBookmarkButtonNotification | |
| 125 object:self | |
| 126 userInfo:dict]; | |
| 127 return; | |
| 128 } | |
| 129 node = node->parent(); | |
| 130 } | |
| 131 } | |
| 132 | 110 |
| 133 - (void)stopPulsingBookmarkButton { | 111 bookmarkBubbleObserver_->OnBookmarkBubbleHidden(); |
| 134 if (!pulsingBookmarkNode_) | 112 bookmarkBubbleObserver_ = nullptr; |
| 135 return; | |
| 136 NSValue *value = [NSValue valueWithPointer:pulsingBookmarkNode_]; | |
| 137 if (bookmarkObserver_) | |
| 138 bookmarkObserver_->StopObservingNode(pulsingBookmarkNode_); | |
| 139 pulsingBookmarkNode_ = NULL; | |
| 140 NSDictionary *dict = [NSDictionary | |
| 141 dictionaryWithObjectsAndKeys:value, | |
| 142 bookmark_button::kBookmarkKey, | |
| 143 [NSNumber numberWithBool:NO], | |
| 144 bookmark_button::kBookmarkPulseFlagKey, | |
| 145 nil]; | |
| 146 [[NSNotificationCenter defaultCenter] | |
| 147 postNotificationName:bookmark_button::kPulseBookmarkButtonNotification | |
| 148 object:self | |
| 149 userInfo:dict]; | |
| 150 } | 113 } |
| 151 | 114 |
| 152 // Close the bookmark bubble without changing anything. Unlike a | 115 // Close the bookmark bubble without changing anything. Unlike a |
| 153 // typical dialog's OK/Cancel, where Cancel is "do nothing", all | 116 // typical dialog's OK/Cancel, where Cancel is "do nothing", all |
| 154 // buttons on the bubble have the capacity to change the bookmark | 117 // buttons on the bubble have the capacity to change the bookmark |
| 155 // model. This is an IBOutlet-looking entry point to remove the | 118 // model. This is an IBOutlet-looking entry point to remove the |
| 156 // dialog without touching the model. | 119 // dialog without touching the model. |
| 157 - (void)dismissWithoutEditing:(id)sender { | 120 - (void)dismissWithoutEditing:(id)sender { |
| 158 [self close]; | 121 [self close]; |
| 159 } | 122 } |
| 160 | 123 |
| 161 - (void)windowWillClose:(NSNotification*)notification { | 124 - (void)windowWillClose:(NSNotification*)notification { |
| 162 // We caught a close so we don't need to watch for the parent closing. | 125 // We caught a close so we don't need to watch for the parent closing. |
| 163 bookmarkObserver_.reset(); | 126 bookmarkObserver_.reset(); |
| 164 [self stopPulsingBookmarkButton]; | 127 [self notifyBubbleClosed]; |
| 165 [super windowWillClose:notification]; | 128 [super windowWillClose:notification]; |
| 166 } | 129 } |
| 167 | 130 |
| 168 // Override -[BaseBubbleController showWindow:] to tweak bubble location and | 131 // Override -[BaseBubbleController showWindow:] to tweak bubble location and |
| 169 // set up UI elements. | 132 // set up UI elements. |
| 170 - (void)showWindow:(id)sender { | 133 - (void)showWindow:(id)sender { |
| 171 NSWindow* window = [self window]; // Force load the NIB. | 134 NSWindow* window = [self window]; // Force load the NIB. |
| 172 NSWindow* parentWindow = self.parentWindow; | 135 NSWindow* parentWindow = self.parentWindow; |
| 173 BrowserWindowController* bwc = | 136 BrowserWindowController* bwc = |
| 174 [BrowserWindowController browserWindowControllerForWindow:parentWindow]; | 137 [BrowserWindowController browserWindowControllerForWindow:parentWindow]; |
| 175 [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; | |
| 176 | 138 |
| 177 InfoBubbleView* bubble = self.bubble; | 139 InfoBubbleView* bubble = self.bubble; |
| 178 [bubble setArrowLocation:info_bubble::kTopRight]; | 140 [bubble setArrowLocation:info_bubble::kTopRight]; |
| 179 | 141 |
| 180 // Insure decent positioning even in the absence of a browser controller, | 142 // Insure decent positioning even in the absence of a browser controller, |
| 181 // which will occur for some unit tests. | 143 // which will occur for some unit tests. |
| 182 NSPoint arrowTip = bwc ? [bwc bookmarkBubblePoint] : | 144 NSPoint arrowTip = bwc ? [bwc bookmarkBubblePoint] : |
| 183 NSMakePoint([window frame].size.width, [window frame].size.height); | 145 NSMakePoint([window frame].size.width, [window frame].size.height); |
| 184 arrowTip = [parentWindow convertBaseToScreen:arrowTip]; | 146 arrowTip = [parentWindow convertBaseToScreen:arrowTip]; |
| 185 NSPoint bubbleArrowTip = [bubble arrowTip]; | 147 NSPoint bubbleArrowTip = [bubble arrowTip]; |
| 186 bubbleArrowTip = [bubble convertPoint:bubbleArrowTip toView:nil]; | 148 bubbleArrowTip = [bubble convertPoint:bubbleArrowTip toView:nil]; |
| 187 arrowTip.y -= bubbleArrowTip.y; | 149 arrowTip.y -= bubbleArrowTip.y; |
| 188 arrowTip.x -= bubbleArrowTip.x; | 150 arrowTip.x -= bubbleArrowTip.x; |
| 189 [window setFrameOrigin:arrowTip]; | 151 [window setFrameOrigin:arrowTip]; |
| 190 | 152 |
| 191 // Default is IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK; "Bookmark". | 153 // Default is IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK; "Bookmark". |
| 192 // If adding for the 1st time the string becomes "Bookmark Added!" | 154 // If adding for the 1st time the string becomes "Bookmark Added!" |
| 193 if (!alreadyBookmarked_) { | 155 if (!alreadyBookmarked_) { |
| 194 NSString* title = | 156 NSString* title = |
| 195 l10n_util::GetNSString(IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED); | 157 l10n_util::GetNSString(IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED); |
| 196 [bigTitle_ setStringValue:title]; | 158 [bigTitle_ setStringValue:title]; |
| 197 } | 159 } |
| 198 | 160 |
| 199 [self fillInFolderList]; | 161 [self fillInFolderList]; |
| 200 | 162 |
| 201 // Ping me when things change out from under us. Unlike a normal | 163 // Ping me when things change out from under us. Unlike a normal |
| 202 // dialog, the bookmark bubble's cancel: means "don't add this as a | 164 // dialog, the bookmark bubble's cancel: means "don't add this as a |
| 203 // bookmark", not "cancel editing". We must take extra care to not | 165 // bookmark", not "cancel editing". We must take extra care to not |
| 204 // touch the bookmark in this selector. | 166 // touch the bookmark in this selector. |
| 205 bookmarkObserver_.reset( | 167 bookmarkObserver_.reset(new BookmarkModelObserverForCocoa(model_, ^(BOOL) { |
|
tapted
2015/08/25 01:13:21
is the BOOL argument to the closure still needed?
jackhou1
2015/08/25 04:32:29
Nope, removed.
| |
| 206 new BookmarkModelObserverForCocoa(model_, ^(BOOL nodeWasDeleted) { | 168 [self dismissWithoutEditing:nil]; |
| 207 // If a watched node was deleted, the pointer to the pulsing button | 169 })); |
| 208 // is likely stale. | |
| 209 if (nodeWasDeleted) | |
| 210 pulsingBookmarkNode_ = NULL; | |
| 211 [self dismissWithoutEditing:nil]; | |
| 212 })); | |
| 213 bookmarkObserver_->StartObservingNode(node_); | 170 bookmarkObserver_->StartObservingNode(node_); |
| 214 | 171 |
| 215 // Pulse something interesting on the bookmark bar. | |
| 216 [self startPulsingBookmarkButton:node_]; | |
| 217 | |
| 218 [parentWindow addChildWindow:window ordered:NSWindowAbove]; | 172 [parentWindow addChildWindow:window ordered:NSWindowAbove]; |
| 219 [window makeKeyAndOrderFront:self]; | 173 [window makeKeyAndOrderFront:self]; |
| 220 [self registerKeyStateEventTap]; | 174 [self registerKeyStateEventTap]; |
| 175 | |
| 176 bookmarkBubbleObserver_->OnBookmarkBubbleShown(node_); | |
| 221 } | 177 } |
| 222 | 178 |
| 223 - (void)close { | 179 - (void)close { |
| 224 [[BrowserWindowController browserWindowControllerForWindow:self.parentWindow] | 180 [[BrowserWindowController browserWindowControllerForWindow:self.parentWindow] |
| 225 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO]; | 181 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO]; |
| 226 | 182 |
| 227 [super close]; | 183 [super close]; |
| 228 } | 184 } |
| 229 | 185 |
| 230 // Shows the bookmark editor sheet for more advanced editing. | 186 // Shows the bookmark editor sheet for more advanced editing. |
| 231 - (void)showEditor { | 187 - (void)showEditor { |
| 232 [self ok:self]; | 188 [self ok:self]; |
| 233 // Send the action up through the responder chain. | 189 // Send the action up through the responder chain. |
| 234 [NSApp sendAction:@selector(editBookmarkNode:) to:nil from:self]; | 190 [NSApp sendAction:@selector(editBookmarkNode:) to:nil from:self]; |
| 235 } | 191 } |
| 236 | 192 |
| 237 - (IBAction)edit:(id)sender { | 193 - (IBAction)edit:(id)sender { |
| 238 content::RecordAction(UserMetricsAction("BookmarkBubble_Edit")); | 194 content::RecordAction(UserMetricsAction("BookmarkBubble_Edit")); |
| 239 [self showEditor]; | 195 [self showEditor]; |
| 240 } | 196 } |
| 241 | 197 |
| 242 - (IBAction)ok:(id)sender { | 198 - (IBAction)ok:(id)sender { |
| 243 [self stopPulsingBookmarkButton]; // before parent changes | |
| 244 [self updateBookmarkNode]; | 199 [self updateBookmarkNode]; |
| 245 [self close]; | 200 [self close]; |
| 246 } | 201 } |
| 247 | 202 |
| 248 // By implementing this, ESC causes the window to go away. If clicking the | 203 // By implementing this, ESC causes the window to go away. If clicking the |
| 249 // star was what prompted this bubble to appear (i.e., not already bookmarked), | 204 // star was what prompted this bubble to appear (i.e., not already bookmarked), |
| 250 // remove the bookmark. | 205 // remove the bookmark. |
| 251 - (IBAction)cancel:(id)sender { | 206 - (IBAction)cancel:(id)sender { |
| 252 if (!alreadyBookmarked_) { | 207 if (!alreadyBookmarked_) { |
| 253 // |-remove:| calls |-close| so don't do it. | 208 // |-remove:| calls |-close| so don't do it. |
| 254 [self remove:sender]; | 209 [self remove:sender]; |
| 255 } else { | 210 } else { |
| 256 [self stopPulsingBookmarkButton]; | |
| 257 [self dismissWithoutEditing:nil]; | 211 [self dismissWithoutEditing:nil]; |
| 258 } | 212 } |
| 259 } | 213 } |
| 260 | 214 |
| 261 - (IBAction)remove:(id)sender { | 215 - (IBAction)remove:(id)sender { |
| 262 [self stopPulsingBookmarkButton]; | |
| 263 bookmarks::RemoveAllBookmarks(model_, node_->url()); | 216 bookmarks::RemoveAllBookmarks(model_, node_->url()); |
| 264 content::RecordAction(UserMetricsAction("BookmarkBubble_Unstar")); | 217 content::RecordAction(UserMetricsAction("BookmarkBubble_Unstar")); |
| 265 node_ = NULL; // no longer valid | 218 node_ = NULL; // no longer valid |
| 266 [self ok:sender]; | 219 [self ok:sender]; |
| 267 } | 220 } |
| 268 | 221 |
| 269 // The controller is the target of the pop up button box action so it can | 222 // The controller is the target of the pop up button box action so it can |
| 270 // handle when "choose another folder" was picked. | 223 // handle when "choose another folder" was picked. |
| 271 - (IBAction)folderChanged:(id)sender { | 224 - (IBAction)folderChanged:(id)sender { |
| 272 DCHECK([sender isEqual:folderPopUpButton_]); | 225 DCHECK([sender isEqual:folderPopUpButton_]); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 | 304 |
| 352 @end // BookmarkBubbleController | 305 @end // BookmarkBubbleController |
| 353 | 306 |
| 354 | 307 |
| 355 @implementation BookmarkBubbleController (ExposedForUnitTesting) | 308 @implementation BookmarkBubbleController (ExposedForUnitTesting) |
| 356 | 309 |
| 357 - (NSView*)syncPromoPlaceholder { | 310 - (NSView*)syncPromoPlaceholder { |
| 358 return syncPromoPlaceholder_; | 311 return syncPromoPlaceholder_; |
| 359 } | 312 } |
| 360 | 313 |
| 314 - (bookmarks::BookmarkBubbleObserver*)bookmarkBubbleObserver { | |
| 315 return bookmarkBubbleObserver_; | |
| 316 } | |
| 317 | |
| 361 + (NSString*)chooseAnotherFolderString { | 318 + (NSString*)chooseAnotherFolderString { |
| 362 return l10n_util::GetNSStringWithFixup( | 319 return l10n_util::GetNSStringWithFixup( |
| 363 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER); | 320 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER); |
| 364 } | 321 } |
| 365 | 322 |
| 366 // For the given folder node, walk the tree and add folder names to | 323 // For the given folder node, walk the tree and add folder names to |
| 367 // the given pop up button. | 324 // the given pop up button. |
| 368 - (void)addFolderNodes:(const BookmarkNode*)parent | 325 - (void)addFolderNodes:(const BookmarkNode*)parent |
| 369 toPopUpButton:(NSPopUpButton*)button | 326 toPopUpButton:(NSPopUpButton*)button |
| 370 indentation:(int)indentation { | 327 indentation:(int)indentation { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue]; | 361 NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue]; |
| 405 DCHECK(idx != -1); | 362 DCHECK(idx != -1); |
| 406 [folderPopUpButton_ selectItemAtIndex:idx]; | 363 [folderPopUpButton_ selectItemAtIndex:idx]; |
| 407 } | 364 } |
| 408 | 365 |
| 409 - (NSPopUpButton*)folderPopUpButton { | 366 - (NSPopUpButton*)folderPopUpButton { |
| 410 return folderPopUpButton_; | 367 return folderPopUpButton_; |
| 411 } | 368 } |
| 412 | 369 |
| 413 @end // implementation BookmarkBubbleController(ExposedForUnitTesting) | 370 @end // implementation BookmarkBubbleController(ExposedForUnitTesting) |
| OLD | NEW |