Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm

Issue 1308293002: [Mac] Refactor bookmark pulsing into BookmarkBubbleObserverCocoa. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@bookmarkeditor
Patch Set: Address comments. Update unit_tests. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 bubbleObserver:(bookmarks::BookmarkBubbleObserver*)bubbleObserver
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_ = bubbleObserver;
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
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_, ^() {
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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698