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

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: Review comments 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:
136 145 ^BOOL(id popup, NSUInteger i, BOOL* stop) {
137 // Find the popup for the given ID. 146 return [popup notificationID] == notificationID;
138 NSUInteger index = 0; 147 }];
139 MCPopupController* popup = nil; 148 // The notification may not be on screen.
140 for (MCPopupController* candidate in popups_.get()) { 149 if (index == NSNotFound)
141 if ([candidate notificationID] == notificationID) {
142 popup = candidate;
143 } else {
144 onScreen.insert([candidate notificationID]);
145 }
146
147 // If the popup has not yet been found, increase the index.
148 if (!popup)
149 ++index;
150 }
151
152 if (!popup)
153 return; 150 return;
154 151
155 // Calculate its height and then close it. 152 // Find the corresponding model object for the ID. This may be a replaced
156 CGFloat delta = NSHeight([[popup window] frame]) + 153 // notification, so the controller's current model object may be stale.
157 message_center::kMarginBetweenItems; 154 const message_center::Notification* notification = NULL;
158 [popup close]; 155 const auto& modelPopups = messageCenter_->GetPopupNotifications();
159 [popups_ removeObjectAtIndex:index]; 156 for (auto it = modelPopups.begin(); it != modelPopups.end(); ++it) {
157 if ((*it)->id() == notificationID) {
158 notification = *it;
159 break;
160 }
161 }
162 DCHECK(notification);
163 if (!notification)
164 return;
160 165
161 // Shift all the popups up. 166 MCPopupController* popup = [popups_ objectAtIndex:index];
162 for ( ; index < [popups_ count]; ++index) {
163 NSWindow* window = [[popups_ objectAtIndex:index] window];
164 NSPoint origin = [window frame].origin;
165 origin.y += delta;
166 [window setFrameOrigin:origin];
167 }
168 167
169 // Display any new popups that can now fit on screen. 168 CGFloat oldHeight =
170 const auto& allPopups = messageCenter_->GetPopupNotifications(); 169 NSHeight([[[popup notificationController] view] frame]);
171 for (auto it = allPopups.begin(); it != allPopups.end(); ++it) { 170 CGFloat newHeight = NSHeight(
172 if (onScreen.find((*it)->id()) == onScreen.end()) { 171 [[popup notificationController] updateNotification:notification]);
173 // If there's no room left on screen to display notifications, stop 172
174 // trying. 173 // The notification has changed height. This requires updating the popup
175 if (![self addNotification:*it]) 174 // window and any popups that come below it.
176 break; 175 if (oldHeight != newHeight) {
177 } 176 NSRect popupFrame = [[popup window] frame];
177 popupFrame.size.height += newHeight - oldHeight;
178 [[popup window] setFrame:popupFrame display:YES];
179
180 // Start re-layout of notifications at this index, so that it readjusts
181 // the Y origin of this notification.
182 [self layoutNotificationsStartingAt:index];
178 } 183 }
179 } 184 }
180 185
186 - (void)removeNotification:(const std::string&)notificationID {
187 NSUInteger index = [popups_ indexOfObjectPassingTest:
188 ^BOOL(id popup, NSUInteger index, BOOL* stop) {
189 return [popup notificationID] == notificationID;
190 }];
191 // The notification may not be on screen.
192 if (index == NSNotFound)
193 return;
194
195 [[popups_ objectAtIndex:index] close];
196 [popups_ removeObjectAtIndex:index];
197
198 if (index < [popups_ count])
199 [self layoutNotificationsStartingAt:index];
200 }
201
181 - (void)removeAllNotifications { 202 - (void)removeAllNotifications {
182 [popups_ makeObjectsPerformSelector:@selector(close)]; 203 [popups_ makeObjectsPerformSelector:@selector(close)];
183 [popups_ removeAllObjects]; 204 [popups_ removeAllObjects];
184 } 205 }
185 206
207 - (void)layoutNotificationsStartingAt:(NSUInteger)index {
208 NSRect screenFrame = [self screenFrame];
209 std::set<std::string> onScreen;
210
211 // Calcluate the bottom edge of the |index - 1|th popup.
212 CGFloat maxY = 0;
213 if (index == 0)
214 maxY = NSMaxY(screenFrame);
215 else
216 maxY = NSMinY([[[popups_ objectAtIndex:index - 1] window] frame]);
217
218 // Collect the IDs of popups that are currently on screen.
219 for (NSUInteger i = 0; i < index; ++i)
220 onScreen.insert([[popups_ objectAtIndex:i] notificationID]);
221
222 // Iterate between [index, count) notifications and reposition each. If one
223 // does not fit on screen, close it and any other on-screen popups that come
224 // after it.
225 NSUInteger removeAt = NSNotFound;
226 for (NSUInteger i = index; i < [popups_ count]; ++i) {
227 MCPopupController* popup = [popups_ objectAtIndex:i];
228 NSRect frame = [[popup window] frame];
229 frame.origin.y = maxY - message_center::kMarginBetweenItems -
230 NSHeight(frame);
231
232 // If this popup does not fit on screen, stop repositioning and close this
233 // and subsequent popups.
234 if (NSMinY(frame) < NSMinY(screenFrame)) {
235 removeAt = i;
236 break;
237 }
238
239 [[popup window] setFrame:frame display:YES];
240 onScreen.insert([popup notificationID]);
241
242 // Set the new maximum Y to be the bottom of this notification.
243 maxY = NSMinY(frame);
244 }
245
246 if (removeAt != NSNotFound) {
247 // Remove any popups that are on screen but no longer fit.
248 while ([popups_ count] >= removeAt) {
249 [[popups_ lastObject] close];
250 [popups_ removeLastObject];
251 }
252 } else {
253 // Display any new popups that can now fit on screen.
254 const auto& allPopups = messageCenter_->GetPopupNotifications();
255 for (auto it = allPopups.begin(); it != allPopups.end(); ++it) {
256 if (onScreen.find((*it)->id()) == onScreen.end()) {
257 // If there's no room left on screen to display notifications, stop
258 // trying.
259 if (![self addNotification:*it])
260 break;
261 }
262 }
263 }
264 }
265
186 @end 266 @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