OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/mac/mac_util.h" | 8 #include "base/mac/mac_util.h" |
9 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
10 #include "chrome/browser/bookmarks/bookmark_model.h" | 10 #include "chrome/browser/bookmarks/bookmark_model.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 // An object to represent the ChooseAnotherFolder item in the pop up. | 63 // An object to represent the ChooseAnotherFolder item in the pop up. |
64 @interface ChooseAnotherFolder : NSObject | 64 @interface ChooseAnotherFolder : NSObject |
65 @end | 65 @end |
66 | 66 |
67 @implementation ChooseAnotherFolder | 67 @implementation ChooseAnotherFolder |
68 @end | 68 @end |
69 | 69 |
70 @interface BookmarkBubbleController (PrivateAPI) | 70 @interface BookmarkBubbleController (PrivateAPI) |
71 - (void)updateBookmarkNode; | 71 - (void)updateBookmarkNode; |
72 - (void)fillInFolderList; | 72 - (void)fillInFolderList; |
73 - (void)parentWindowWillClose:(NSNotification*)notification; | |
74 @end | 73 @end |
75 | 74 |
76 @implementation BookmarkBubbleController | 75 @implementation BookmarkBubbleController |
77 | 76 |
78 @synthesize node = node_; | 77 @synthesize node = node_; |
79 | 78 |
80 + (id)chooseAnotherFolderObject { | 79 + (id)chooseAnotherFolderObject { |
81 // Singleton object to act as a representedObject for the "choose another | 80 // Singleton object to act as a representedObject for the "choose another |
82 // folder" item in the pop up. | 81 // folder" item in the pop up. |
83 static ChooseAnotherFolder* object = nil; | 82 static ChooseAnotherFolder* object = nil; |
84 if (!object) { | 83 if (!object) { |
85 object = [[ChooseAnotherFolder alloc] init]; | 84 object = [[ChooseAnotherFolder alloc] init]; |
86 } | 85 } |
87 return object; | 86 return object; |
88 } | 87 } |
89 | 88 |
90 - (id)initWithParentWindow:(NSWindow*)parentWindow | 89 - (id)initWithParentWindow:(NSWindow*)parentWindow |
91 model:(BookmarkModel*)model | 90 model:(BookmarkModel*)model |
92 node:(const BookmarkNode*)node | 91 node:(const BookmarkNode*)node |
93 alreadyBookmarked:(BOOL)alreadyBookmarked { | 92 alreadyBookmarked:(BOOL)alreadyBookmarked { |
94 NSString* nibPath = | 93 if ((self = [super initWithWindowNibPath:@"BookmarkBubble" |
95 [base::mac::FrameworkBundle() pathForResource:@"BookmarkBubble" | 94 parentWindow:parentWindow |
96 ofType:@"nib"]; | 95 anchoredAt:NSZeroPoint])) { |
97 if ((self = [super initWithWindowNibPath:nibPath owner:self])) { | |
98 parentWindow_ = parentWindow; | |
99 model_ = model; | 96 model_ = model; |
100 node_ = node; | 97 node_ = node; |
101 alreadyBookmarked_ = alreadyBookmarked; | 98 alreadyBookmarked_ = alreadyBookmarked; |
102 | |
103 // Watch to see if the parent window closes, and if so, close this one. | |
104 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; | |
105 [center addObserver:self | |
106 selector:@selector(parentWindowWillClose:) | |
107 name:NSWindowWillCloseNotification | |
108 object:parentWindow_]; | |
109 } | 99 } |
110 return self; | 100 return self; |
111 } | 101 } |
112 | 102 |
113 - (void)awakeFromNib { | 103 - (void)awakeFromNib { |
104 [super awakeFromNib]; | |
105 | |
114 // Check if NSTextFieldCell supports the method. This check is in place as | 106 // Check if NSTextFieldCell supports the method. This check is in place as |
115 // only 10.6 and greater support the setUsesSingleLineMode method. | 107 // only 10.6 and greater support the setUsesSingleLineMode method. |
116 // TODO(kushi.p): Remove this when the project hits a 10.6+ only state. | 108 // TODO(kushi.p): Remove this when the project hits a 10.6+ only state. |
117 NSTextFieldCell* nameFieldCell_ = [nameTextField_ cell]; | 109 NSTextFieldCell* nameFieldCell_ = [nameTextField_ cell]; |
118 if ([nameFieldCell_ | 110 if ([nameFieldCell_ |
119 respondsToSelector:@selector(setUsesSingleLineMode:)]) { | 111 respondsToSelector:@selector(setUsesSingleLineMode:)]) { |
120 [nameFieldCell_ setUsesSingleLineMode:YES]; | 112 [nameFieldCell_ setUsesSingleLineMode:YES]; |
121 } | 113 } |
122 } | 114 } |
123 | 115 |
124 - (void)dealloc { | |
125 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
126 [super dealloc]; | |
127 } | |
128 | |
129 // If this is a new bookmark somewhere visible (e.g. on the bookmark | 116 // If this is a new bookmark somewhere visible (e.g. on the bookmark |
130 // bar), pulse it. Else, call ourself recursively with our parent | 117 // bar), pulse it. Else, call ourself recursively with our parent |
131 // until we find something visible to pulse. | 118 // until we find something visible to pulse. |
132 - (void)startPulsingBookmarkButton:(const BookmarkNode*)node { | 119 - (void)startPulsingBookmarkButton:(const BookmarkNode*)node { |
133 while (node) { | 120 while (node) { |
134 if ((node->parent() == model_->bookmark_bar_node()) || | 121 if ((node->parent() == model_->bookmark_bar_node()) || |
135 (node == model_->other_node())) { | 122 (node == model_->other_node())) { |
136 pulsingBookmarkNode_ = node; | 123 pulsingBookmarkNode_ = node; |
137 NSValue *value = [NSValue valueWithPointer:node]; | 124 NSValue *value = [NSValue valueWithPointer:node]; |
138 NSDictionary *dict = [NSDictionary | 125 NSDictionary *dict = [NSDictionary |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 | 157 |
171 // Close the bookmark bubble without changing anything. Unlike a | 158 // Close the bookmark bubble without changing anything. Unlike a |
172 // typical dialog's OK/Cancel, where Cancel is "do nothing", all | 159 // typical dialog's OK/Cancel, where Cancel is "do nothing", all |
173 // buttons on the bubble have the capacity to change the bookmark | 160 // buttons on the bubble have the capacity to change the bookmark |
174 // model. This is an IBOutlet-looking entry point to remove the | 161 // model. This is an IBOutlet-looking entry point to remove the |
175 // dialog without touching the model. | 162 // dialog without touching the model. |
176 - (void)dismissWithoutEditing:(id)sender { | 163 - (void)dismissWithoutEditing:(id)sender { |
177 [self close]; | 164 [self close]; |
178 } | 165 } |
179 | 166 |
180 - (void)parentWindowWillClose:(NSNotification*)notification { | |
181 [self close]; | |
182 } | |
183 | |
184 - (void)windowWillClose:(NSNotification*)notification { | 167 - (void)windowWillClose:(NSNotification*)notification { |
185 // We caught a close so we don't need to watch for the parent closing. | 168 // We caught a close so we don't need to watch for the parent closing. |
186 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
187 bookmark_observer_.reset(NULL); | 169 bookmark_observer_.reset(NULL); |
188 chrome_observer_.reset(NULL); | 170 chrome_observer_.reset(NULL); |
189 [self stopPulsingBookmarkButton]; | 171 [self stopPulsingBookmarkButton]; |
190 [self autorelease]; | 172 [super windowWillClose:notification]; |
191 } | 173 } |
192 | 174 |
193 // We want this to be a child of a browser window. addChildWindow: | 175 // We want this to be a child of a browser window. addChildWindow: |
194 // (called from this function) will bring the window on-screen; | 176 // (called from this function) will bring the window on-screen; |
195 // unfortunately, [NSWindowController showWindow:] will also bring it | 177 // unfortunately, [NSWindowController showWindow:] will also bring it |
Nico
2012/03/15 21:21:34
Is this comment still needed? Maybe just "Override
Robert Sesek
2012/03/16 15:31:08
Done.
| |
196 // on-screen (but will cause unexpected changes to the window's | 178 // on-screen (but will cause unexpected changes to the window's |
197 // position). We cannot have an addChildWindow: and a subsequent | 179 // position). We cannot have an addChildWindow: and a subsequent |
198 // showWindow:. Thus, we have our own version. | 180 // showWindow:. Thus, we have our own version. |
199 - (void)showWindow:(id)sender { | 181 - (void)showWindow:(id)sender { |
182 NSWindow* window = [self window]; // Force load the NIB. | |
183 NSWindow* parentWindow = self.parentWindow; | |
200 BrowserWindowController* bwc = | 184 BrowserWindowController* bwc = |
201 [BrowserWindowController browserWindowControllerForWindow:parentWindow_]; | 185 [BrowserWindowController browserWindowControllerForWindow:parentWindow]; |
202 [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; | 186 [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; |
203 NSWindow* window = [self window]; // completes nib load | 187 |
204 [bubble_ setArrowLocation:info_bubble::kTopRight]; | 188 InfoBubbleView* bubble = self.bubble; |
189 [bubble setArrowLocation:info_bubble::kTopRight]; | |
190 | |
205 // Insure decent positioning even in the absence of a browser controller, | 191 // Insure decent positioning even in the absence of a browser controller, |
206 // which will occur for some unit tests. | 192 // which will occur for some unit tests. |
207 NSPoint arrowtip = bwc ? [bwc bookmarkBubblePoint] : | 193 NSPoint arrowTip = bwc ? [bwc bookmarkBubblePoint] : |
208 NSMakePoint([window frame].size.width, [window frame].size.height); | 194 NSMakePoint([window frame].size.width, [window frame].size.height); |
209 NSPoint origin = [parentWindow_ convertBaseToScreen:arrowtip]; | 195 arrowTip = [parentWindow convertBaseToScreen:arrowTip]; |
210 NSPoint bubbleArrowtip = [bubble_ arrowTip]; | 196 NSPoint bubbleArrowTip = [bubble arrowTip]; |
211 bubbleArrowtip = [bubble_ convertPoint:bubbleArrowtip toView:nil]; | 197 bubbleArrowTip = [bubble convertPoint:bubbleArrowTip toView:nil]; |
212 origin.y -= bubbleArrowtip.y; | 198 arrowTip.y -= bubbleArrowTip.y; |
213 origin.x -= bubbleArrowtip.x; | 199 arrowTip.x -= bubbleArrowTip.x; |
214 [window setFrameOrigin:origin]; | 200 [window setFrameOrigin:arrowTip]; |
215 [parentWindow_ addChildWindow:window ordered:NSWindowAbove]; | 201 |
216 // Default is IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK; "Bookmark". | 202 // Default is IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK; "Bookmark". |
217 // If adding for the 1st time the string becomes "Bookmark Added!" | 203 // If adding for the 1st time the string becomes "Bookmark Added!" |
218 if (!alreadyBookmarked_) { | 204 if (!alreadyBookmarked_) { |
219 NSString* title = | 205 NSString* title = |
220 l10n_util::GetNSString(IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED); | 206 l10n_util::GetNSString(IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED); |
221 [bigTitle_ setStringValue:title]; | 207 [bigTitle_ setStringValue:title]; |
222 } | 208 } |
223 | 209 |
224 [self fillInFolderList]; | 210 [self fillInFolderList]; |
225 | 211 |
226 // Ping me when things change out from under us. Unlike a normal | 212 // Ping me when things change out from under us. Unlike a normal |
227 // dialog, the bookmark bubble's cancel: means "don't add this as a | 213 // dialog, the bookmark bubble's cancel: means "don't add this as a |
228 // bookmark", not "cancel editing". We must take extra care to not | 214 // bookmark", not "cancel editing". We must take extra care to not |
229 // touch the bookmark in this selector. | 215 // touch the bookmark in this selector. |
230 bookmark_observer_.reset(new BookmarkModelObserverForCocoa( | 216 bookmark_observer_.reset(new BookmarkModelObserverForCocoa( |
231 node_, model_, | 217 node_, model_, |
232 self, | 218 self, |
233 @selector(dismissWithoutEditing:))); | 219 @selector(dismissWithoutEditing:))); |
234 chrome_observer_.reset(new BookmarkBubbleNotificationBridge( | 220 chrome_observer_.reset(new BookmarkBubbleNotificationBridge( |
235 self, @selector(dismissWithoutEditing:))); | 221 self, @selector(dismissWithoutEditing:))); |
236 | 222 |
237 // Pulse something interesting on the bookmark bar. | 223 // Pulse something interesting on the bookmark bar. |
238 [self startPulsingBookmarkButton:node_]; | 224 [self startPulsingBookmarkButton:node_]; |
239 | 225 |
226 [parentWindow addChildWindow:window ordered:NSWindowAbove]; | |
240 [window makeKeyAndOrderFront:self]; | 227 [window makeKeyAndOrderFront:self]; |
241 } | 228 } |
242 | 229 |
243 - (void)close { | 230 - (void)close { |
244 [[BrowserWindowController browserWindowControllerForWindow:parentWindow_] | 231 [[BrowserWindowController browserWindowControllerForWindow:self.parentWindow] |
245 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO]; | 232 releaseBarVisibilityForOwner:self withAnimation:YES delay:NO]; |
246 [parentWindow_ removeChildWindow:[self window]]; | |
247 | |
248 // If you quit while the bubble is open, sometimes we get a | |
249 // DidResignKey before we get our parent's WindowWillClose and | |
250 // sometimes not. We protect against a multiple close (or reference | |
251 // to parentWindow_ at a bad time) by clearing it out once we're | |
252 // done, and by removing ourself from future notifications. | |
253 [[NSNotificationCenter defaultCenter] | |
254 removeObserver:self | |
255 name:NSWindowWillCloseNotification | |
256 object:parentWindow_]; | |
257 parentWindow_ = nil; | |
258 | 233 |
259 [super close]; | 234 [super close]; |
260 } | 235 } |
261 | 236 |
262 // Shows the bookmark editor sheet for more advanced editing. | 237 // Shows the bookmark editor sheet for more advanced editing. |
263 - (void)showEditor { | 238 - (void)showEditor { |
264 [self ok:self]; | 239 [self ok:self]; |
265 // Send the action up through the responder chain. | 240 // Send the action up through the responder chain. |
266 [NSApp sendAction:@selector(editBookmarkNode:) to:nil from:self]; | 241 [NSApp sendAction:@selector(editBookmarkNode:) to:nil from:self]; |
267 } | 242 } |
(...skipping 29 matching lines...) Expand all Loading... | |
297 [self ok:sender]; | 272 [self ok:sender]; |
298 } | 273 } |
299 | 274 |
300 // The controller is the target of the pop up button box action so it can | 275 // The controller is the target of the pop up button box action so it can |
301 // handle when "choose another folder" was picked. | 276 // handle when "choose another folder" was picked. |
302 - (IBAction)folderChanged:(id)sender { | 277 - (IBAction)folderChanged:(id)sender { |
303 DCHECK([sender isEqual:folderPopUpButton_]); | 278 DCHECK([sender isEqual:folderPopUpButton_]); |
304 // It is possible that due to model change our parent window has been closed | 279 // It is possible that due to model change our parent window has been closed |
305 // but the popup is still showing and able to notify the controller of a | 280 // but the popup is still showing and able to notify the controller of a |
306 // folder change. We ignore the sender in this case. | 281 // folder change. We ignore the sender in this case. |
307 if (!parentWindow_) | 282 if (!self.parentWindow) |
308 return; | 283 return; |
309 NSMenuItem* selected = [folderPopUpButton_ selectedItem]; | 284 NSMenuItem* selected = [folderPopUpButton_ selectedItem]; |
310 ChooseAnotherFolder* chooseItem = [[self class] chooseAnotherFolderObject]; | 285 ChooseAnotherFolder* chooseItem = [[self class] chooseAnotherFolderObject]; |
311 if ([[selected representedObject] isEqual:chooseItem]) { | 286 if ([[selected representedObject] isEqual:chooseItem]) { |
312 content::RecordAction( | 287 content::RecordAction( |
313 UserMetricsAction("BookmarkBubble_EditFromCombobox")); | 288 UserMetricsAction("BookmarkBubble_EditFromCombobox")); |
314 [self showEditor]; | 289 [self showEditor]; |
315 } | 290 } |
316 } | 291 } |
317 | 292 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
375 [item setRepresentedObject:obj]; | 350 [item setRepresentedObject:obj]; |
376 // Finally, select the current parent. | 351 // Finally, select the current parent. |
377 NSValue* parentValue = [NSValue valueWithPointer:node_->parent()]; | 352 NSValue* parentValue = [NSValue valueWithPointer:node_->parent()]; |
378 NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue]; | 353 NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue]; |
379 [folderPopUpButton_ selectItemAtIndex:idx]; | 354 [folderPopUpButton_ selectItemAtIndex:idx]; |
380 } | 355 } |
381 | 356 |
382 @end // BookmarkBubbleController | 357 @end // BookmarkBubbleController |
383 | 358 |
384 | 359 |
385 @implementation BookmarkBubbleController(ExposedForUnitTesting) | 360 @implementation BookmarkBubbleController (ExposedForUnitTesting) |
386 | 361 |
387 + (NSString*)chooseAnotherFolderString { | 362 + (NSString*)chooseAnotherFolderString { |
388 return l10n_util::GetNSStringWithFixup( | 363 return l10n_util::GetNSStringWithFixup( |
389 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER); | 364 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER); |
390 } | 365 } |
391 | 366 |
392 // For the given folder node, walk the tree and add folder names to | 367 // For the given folder node, walk the tree and add folder names to |
393 // the given pop up button. | 368 // the given pop up button. |
394 - (void)addFolderNodes:(const BookmarkNode*)parent | 369 - (void)addFolderNodes:(const BookmarkNode*)parent |
395 toPopUpButton:(NSPopUpButton*)button | 370 toPopUpButton:(NSPopUpButton*)button |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
428 NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue]; | 403 NSInteger idx = [menu indexOfItemWithRepresentedObject:parentValue]; |
429 DCHECK(idx != -1); | 404 DCHECK(idx != -1); |
430 [folderPopUpButton_ selectItemAtIndex:idx]; | 405 [folderPopUpButton_ selectItemAtIndex:idx]; |
431 } | 406 } |
432 | 407 |
433 - (NSPopUpButton*)folderPopUpButton { | 408 - (NSPopUpButton*)folderPopUpButton { |
434 return folderPopUpButton_; | 409 return folderPopUpButton_; |
435 } | 410 } |
436 | 411 |
437 @end // implementation BookmarkBubbleController(ExposedForUnitTesting) | 412 @end // implementation BookmarkBubbleController(ExposedForUnitTesting) |
OLD | NEW |