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

Side by Side Diff: ui/message_center/cocoa/popup_collection.mm

Issue 14598015: [Mac][MC] Implement notification updates and relayouts. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "ui/message_center/cocoa/popup_collection.h" 5 #import "ui/message_center/cocoa/popup_collection.h"
6 6
7 #include "ui/message_center/cocoa/popup_controller.h" 7 #import "ui/message_center/cocoa/notification_controller.h"
8 #import "ui/message_center/cocoa/popup_controller.h"
8 #include "ui/message_center/message_center.h" 9 #include "ui/message_center/message_center.h"
9 #include "ui/message_center/message_center_constants.h" 10 #include "ui/message_center/message_center_constants.h"
10 #include "ui/message_center/message_center_observer.h" 11 #include "ui/message_center/message_center_observer.h"
11 12
12 @interface MCPopupCollection (Private) 13 @interface MCPopupCollection (Private)
13 // Returns the primary screen's visible frame rectangle. 14 // Returns the primary screen's visible frame rectangle.
14 - (NSRect)screenFrame; 15 - (NSRect)screenFrame;
15 16
16 // Shows a popup, if there is room on-screen, for the given notification. 17 // Shows a popup, if there is room on-screen, for the given notification.
17 // Returns YES if the notification was actually displayed. 18 // Returns YES if the notification was actually displayed.
18 - (BOOL)addNotification:(const message_center::Notification*)notification; 19 - (BOOL)addNotification:(const message_center::Notification*)notification;
19 20
21 // Updates the contents of the notification with the given ID.
22 - (void)updateNotification:(const std::string&)notificationID;
23
20 // Removes a popup from the screen and lays out new notifications that can 24 // Removes a popup from the screen and lays out new notifications that can
21 // now potentially fit on the screen. 25 // now potentially fit on the screen.
22 - (void)removeNotification:(const std::string&)notificationID; 26 - (void)removeNotification:(const std::string&)notificationID;
23 27
24 // Closes all the popups. 28 // Closes all the popups.
25 - (void)removeAllNotifications; 29 - (void)removeAllNotifications;
30
31 // Positions popup notifications for the |index|th notification in |popups_|.
32 // This will put the proper amount of space between popup |index - 1| and
33 // |index| and then any subsequent notifications.
34 - (void)layoutNotificationsStartingAt:(NSUInteger)index;
26 @end 35 @end
27 36
28 namespace { 37 namespace {
29 38
30 class PopupCollectionObserver : public message_center::MessageCenterObserver { 39 class PopupCollectionObserver : public message_center::MessageCenterObserver {
31 public: 40 public:
32 PopupCollectionObserver(message_center::MessageCenter* message_center, 41 PopupCollectionObserver(message_center::MessageCenter* message_center,
33 MCPopupCollection* popup_collection) 42 MCPopupCollection* popup_collection)
34 : message_center_(message_center), 43 : message_center_(message_center),
35 popup_collection_(popup_collection) { 44 popup_collection_(popup_collection) {
(...skipping 15 matching lines...) Expand all
51 } 60 }
52 } 61 }
53 62
54 virtual void OnNotificationRemoved(const std::string& notification_id, 63 virtual void OnNotificationRemoved(const std::string& notification_id,
55 bool user_id) OVERRIDE { 64 bool user_id) OVERRIDE {
56 [popup_collection_ removeNotification:notification_id]; 65 [popup_collection_ removeNotification:notification_id];
57 } 66 }
58 67
59 virtual void OnNotificationUpdated( 68 virtual void OnNotificationUpdated(
60 const std::string& notification_id) OVERRIDE { 69 const std::string& notification_id) OVERRIDE {
61 // TODO(rsesek): Refactor MCNotificationController to support updating. 70 [popup_collection_ updateNotification:notification_id];
62 } 71 }
63 72
64 private: 73 private:
65 message_center::MessageCenter* message_center_; // Weak, global. 74 message_center::MessageCenter* message_center_; // Weak, global.
66 75
67 MCPopupCollection* popup_collection_; // Weak, owns this. 76 MCPopupCollection* popup_collection_; // Weak, owns this.
68 }; 77 };
69 78
70 } // namespace 79 } // namespace
71 80
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 if (y > NSMinY(screenFrame)) { 132 if (y > NSMinY(screenFrame)) {
124 [[popup window] setFrameOrigin:NSMakePoint(x, y)]; 133 [[popup window] setFrameOrigin:NSMakePoint(x, y)];
125 [popup showWindow:self]; 134 [popup showWindow:self];
126 [popups_ addObject:popup]; // Transfer ownership. 135 [popups_ addObject:popup]; // Transfer ownership.
127 return YES; 136 return YES;
128 } 137 }
129 138
130 return NO; 139 return NO;
131 } 140 }
132 141
133 - (void)removeNotification:(const std::string&)notificationID { 142 - (void)updateNotification:(const std::string&)notificationID {
134 // The set of notification IDs that are currently displayed. 143 // Find the controller for this notification ID.
135 std::set<std::string> onScreen; 144 NSUInteger index = [popups_ indexOfObjectPassingTest:
145 ^BOOL(id popup, NSUInteger i, BOOL* stop) {
146 return [popup notificationID] == notificationID;
147 }];
148 // The notification may not be on screen.
149 if (index == NSNotFound)
150 return;
136 151
137 // Find the popup for the given ID. 152 // Find the corresponding model object for the ID. This may be a replaced
138 NSUInteger index = 0; 153 // notification, so the controller's current model object may be stale.
139 MCPopupController* popup = nil; 154 const message_center::Notification* notification = NULL;
140 for (MCPopupController* candidate in popups_.get()) { 155 const auto& modelPopups = messageCenter_->GetPopupNotifications();
141 if ([candidate notificationID] == notificationID) { 156 for (auto it = modelPopups.begin(); it != modelPopups.end(); ++it) {
sail 2013/05/03 21:42:32 nit, this seems like something we'd want to do on
Robert Sesek 2013/05/03 21:59:18 Justin: WDYT? NotificationList has this method but
dewittj 2013/05/03 22:31:37 sounds OK to me
142 popup = candidate; 157 if ((*it)->id() == notificationID) {
143 } else { 158 notification = *it;
144 onScreen.insert([candidate notificationID]); 159 break;
145 } 160 }
146 161 }
147 // If the popup has not yet been found, increase the index. 162 if (!notification) {
148 if (!popup) 163 NOTREACHED();
sail 2013/05/03 21:42:32 I don't think this is a good use of NOTREACHED().
Robert Sesek 2013/05/03 21:59:18 Done.
149 ++index; 164 return;
150 } 165 }
151 166
152 if (!popup) 167 MCPopupController* popup = [popups_ objectAtIndex:index];
153 return;
154 168
155 // Calculate its height and then close it. 169 CGFloat oldHeight =
156 CGFloat delta = NSHeight([[popup window] frame]) + 170 NSHeight([[[popup notificationController] view] frame]);
157 message_center::kMarginBetweenItems; 171 CGFloat newHeight = NSHeight(
158 [popup close]; 172 [[popup notificationController] updateNotification:notification]);
159 [popups_ removeObjectAtIndex:index];
160 173
161 // Shift all the popups up. 174 // The notification has changed height. This requires updating the popup
162 for ( ; index < [popups_ count]; ++index) { 175 // window and any popups that come below it.
163 NSWindow* window = [[popups_ objectAtIndex:index] window]; 176 if (oldHeight != newHeight) {
164 NSPoint origin = [window frame].origin; 177 NSRect popupFrame = [[popup window] frame];
165 origin.y += delta; 178 popupFrame.size.height += newHeight - oldHeight;
166 [window setFrameOrigin:origin]; 179 [[popup window] setFrame:popupFrame display:YES];
167 }
168 180
169 // Display any new popups that can now fit on screen. 181 // Start re-layout of notifications at this index, so that it readjusts
170 const auto& allPopups = messageCenter_->GetPopupNotifications(); 182 // the Y origin of this notification.
171 for (auto it = allPopups.begin(); it != allPopups.end(); ++it) { 183 [self layoutNotificationsStartingAt:index];
172 if (onScreen.find((*it)->id()) == onScreen.end()) {
173 // If there's no room left on screen to display notifications, stop
174 // trying.
175 if (![self addNotification:*it])
176 break;
177 }
178 } 184 }
179 } 185 }
180 186
187 - (void)removeNotification:(const std::string&)notificationID {
188 NSUInteger index = [popups_ indexOfObjectPassingTest:
189 ^BOOL(id popup, NSUInteger index, BOOL* stop) {
190 return [popup notificationID] == notificationID;
191 }];
192 // The notification may not be on screen.
193 if (index == NSNotFound)
194 return;
195
196 [[popups_ objectAtIndex:index] close];
197 [popups_ removeObjectAtIndex:index];
198
199 if (index < [popups_ count])
200 [self layoutNotificationsStartingAt:index];
201 }
202
181 - (void)removeAllNotifications { 203 - (void)removeAllNotifications {
182 [popups_ makeObjectsPerformSelector:@selector(close)]; 204 [popups_ makeObjectsPerformSelector:@selector(close)];
183 [popups_ removeAllObjects]; 205 [popups_ removeAllObjects];
184 } 206 }
185 207
208 - (void)layoutNotificationsStartingAt:(NSUInteger)index {
209 DCHECK_GE(index, 0u);
sail 2013/05/03 21:42:32 since this is unsigned, won't this always be true?
Robert Sesek 2013/05/03 21:59:18 Yes, |index| wasn't always unsigned in a previous
210
211 NSRect screenFrame = [self screenFrame];
212 std::set<std::string> onScreen;
213
214 // Calcluate the bottom edge of the |index - 1|th popup.
215 CGFloat maxY = 0;
216 if (index == 0)
217 maxY = NSMaxY(screenFrame);
218 else
219 maxY = NSMinY([[[popups_ objectAtIndex:index - 1] window] frame]);
220
221 // Collect the IDs of popups that are currently on screen.
222 for (NSUInteger i = 0; i < index; ++i)
223 onScreen.insert([[popups_ objectAtIndex:i] notificationID]);
224
225 // Iterate between [index, count) notifications and reposition each. If one
226 // does not fit on screen, close it and any other on-screen popups that come
227 // after it.
228 NSUInteger removeAt = NSNotFound;
229 for (NSUInteger i = index; i < [popups_ count]; ++i) {
230 MCPopupController* popup = [popups_ objectAtIndex:i];
231 NSRect frame = [[popup window] frame];
232 frame.origin.y = maxY - message_center::kMarginBetweenItems -
233 NSHeight(frame);
234
235 // If this popup does not fit on screen, stop repositioning and close this
236 // and subsequent popups.
237 if (NSMinY(frame) < NSMinY(screenFrame)) {
238 removeAt = i;
239 break;
240 }
241
242 [[popup window] setFrame:frame display:YES];
243 onScreen.insert([popup notificationID]);
244
245 // Set the new maximum Y to be the bottom of this notification.
246 maxY = NSMinY(frame);
247 }
248
249 if (removeAt != NSNotFound) {
250 // Remove any popups that are on screen but no longer fit.
251 while ([popups_ count] >= removeAt) {
252 [[popups_ lastObject] close];
253 [popups_ removeLastObject];
254 }
255 } else {
256 // Display any new popups that can now fit on screen.
257 const auto& allPopups = messageCenter_->GetPopupNotifications();
258 for (auto it = allPopups.begin(); it != allPopups.end(); ++it) {
259 if (onScreen.find((*it)->id()) == onScreen.end()) {
260 // If there's no room left on screen to display notifications, stop
261 // trying.
262 if (![self addNotification:*it])
263 break;
264 }
265 }
266 }
267 }
268
186 @end 269 @end
OLDNEW
« no previous file with comments | « ui/message_center/cocoa/notification_controller_unittest.mm ('k') | ui/message_center/cocoa/popup_collection_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698