OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "browser_actions_controller.h" | 5 #import "browser_actions_controller.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
10 #include "chrome/browser/browser.h" | 10 #include "chrome/browser/browser.h" |
11 #include "chrome/browser/cocoa/extensions/browser_action_button.h" | 11 #include "chrome/browser/cocoa/extensions/browser_action_button.h" |
12 #include "chrome/browser/cocoa/extensions/browser_actions_container_view.h" | 12 #include "chrome/browser/cocoa/extensions/browser_actions_container_view.h" |
13 #include "chrome/browser/cocoa/extensions/extension_popup_controller.h" | 13 #include "chrome/browser/cocoa/extensions/extension_popup_controller.h" |
14 #include "chrome/browser/extensions/extension_browser_event_router.h" | 14 #include "chrome/browser/extensions/extension_browser_event_router.h" |
15 #include "chrome/browser/extensions/extension_toolbar_model.h" | |
15 #include "chrome/browser/extensions/extensions_service.h" | 16 #include "chrome/browser/extensions/extensions_service.h" |
16 #include "chrome/browser/profile.h" | 17 #include "chrome/browser/profile.h" |
17 #include "chrome/browser/tab_contents/tab_contents.h" | 18 #include "chrome/browser/tab_contents/tab_contents.h" |
18 #include "chrome/common/notification_observer.h" | 19 #include "chrome/common/notification_observer.h" |
19 #include "chrome/common/notification_registrar.h" | 20 #include "chrome/common/notification_registrar.h" |
20 | 21 |
21 // The padding between browser action buttons. | 22 // The padding between browser action buttons. |
22 extern const CGFloat kBrowserActionButtonPadding = 3; | 23 extern const CGFloat kBrowserActionButtonPadding = 3; |
23 | 24 |
24 NSString* const kBrowserActionsChangedNotification = @"BrowserActionsChanged"; | 25 NSString* const kBrowserActionsChangedNotification = @"BrowserActionsChanged"; |
25 | 26 |
26 @interface BrowserActionsController(Private) | 27 @interface BrowserActionsController(Private) |
27 - (void)createActionButtonForExtension:(Extension*)extension; | 28 - (void)createActionButtonForExtension:(Extension*)extension |
29 withIndex:(int)index; | |
28 - (void)removeActionButtonForExtension:(Extension*)extension; | 30 - (void)removeActionButtonForExtension:(Extension*)extension; |
29 - (void)repositionActionButtons; | 31 - (void)repositionActionButtons; |
30 - (int)currentTabId; | 32 - (int)currentTabId; |
31 @end | 33 @end |
32 | 34 |
33 // A helper class to proxy extension notifications to the view controller's | 35 // A helper class to proxy extension notifications to the view controller's |
34 // appropriate methods. | 36 // appropriate methods. |
35 class ExtensionsServiceObserverBridge : public NotificationObserver { | 37 class ExtensionsServiceObserverBridge : public NotificationObserver, |
38 public ExtensionToolbarModel::Observer { | |
36 public: | 39 public: |
37 ExtensionsServiceObserverBridge(BrowserActionsController* owner, | 40 ExtensionsServiceObserverBridge(BrowserActionsController* owner, |
38 Profile* profile) : owner_(owner) { | 41 Profile* profile) : owner_(owner) { |
39 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
40 Source<Profile>(profile)); | |
41 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | |
42 Source<Profile>(profile)); | |
43 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, | |
44 Source<Profile>(profile)); | |
45 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 42 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
46 Source<Profile>(profile)); | 43 Source<Profile>(profile)); |
47 } | 44 } |
48 | 45 |
49 // Runs |owner_|'s method corresponding to the event type received from the | |
50 // notification system. | |
51 // Overridden from NotificationObserver. | 46 // Overridden from NotificationObserver. |
52 void Observe(NotificationType type, | 47 void Observe(NotificationType type, |
53 const NotificationSource& source, | 48 const NotificationSource& source, |
54 const NotificationDetails& details) { | 49 const NotificationDetails& details) { |
55 switch (type.value) { | 50 switch (type.value) { |
56 case NotificationType::EXTENSION_LOADED: { | |
57 Extension* extension = Details<Extension>(details).ptr(); | |
58 [owner_ createActionButtonForExtension:extension]; | |
59 [owner_ browserActionVisibilityHasChanged]; | |
60 break; | |
61 } | |
62 case NotificationType::EXTENSION_UNLOADED: | |
63 case NotificationType::EXTENSION_UNLOADED_DISABLED: { | |
64 Extension* extension = Details<Extension>(details).ptr(); | |
65 [owner_ removeActionButtonForExtension:extension]; | |
66 [owner_ browserActionVisibilityHasChanged]; | |
67 break; | |
68 } | |
69 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: { | 51 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: { |
70 ExtensionPopupController* popup = [ExtensionPopupController popup]; | 52 ExtensionPopupController* popup = [ExtensionPopupController popup]; |
71 if (popup && ![popup isClosing]) | 53 if (popup && ![popup isClosing]) |
72 [popup close]; | 54 [popup close]; |
73 | 55 |
74 break; | 56 break; |
75 } | 57 } |
76 default: | 58 default: |
77 NOTREACHED() << L"Unexpected notification"; | 59 NOTREACHED() << L"Unexpected notification"; |
78 } | 60 } |
79 } | 61 } |
80 | 62 |
63 // ExtensionToolbarModel::Observer implementation. | |
64 void BrowserActionAdded(Extension* extension, int index) { | |
65 [owner_ createActionButtonForExtension:extension withIndex:index]; | |
66 } | |
67 | |
68 void BrowserActionRemoved(Extension* extension) { | |
69 [owner_ removeActionButtonForExtension:extension]; | |
70 } | |
71 | |
81 private: | 72 private: |
82 // The object we need to inform when we get a notification. Weak. Owns us. | 73 // The object we need to inform when we get a notification. Weak. Owns us. |
83 BrowserActionsController* owner_; | 74 BrowserActionsController* owner_; |
84 | 75 |
85 // Used for registering to receive notifications and automatic clean up. | 76 // Used for registering to receive notifications and automatic clean up. |
86 NotificationRegistrar registrar_; | 77 NotificationRegistrar registrar_; |
87 | 78 |
88 DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceObserverBridge); | 79 DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceObserverBridge); |
89 }; | 80 }; |
90 | 81 |
91 @implementation BrowserActionsController | 82 @implementation BrowserActionsController |
92 | 83 |
93 - (id)initWithBrowser:(Browser*)browser | 84 - (id)initWithBrowser:(Browser*)browser |
94 containerView:(BrowserActionsContainerView*)container { | 85 containerView:(BrowserActionsContainerView*)container { |
95 DCHECK(browser && container); | 86 DCHECK(browser && container); |
96 | 87 |
97 if ((self = [super init])) { | 88 if ((self = [super init])) { |
98 browser_ = browser; | 89 browser_ = browser; |
99 profile_ = browser->profile(); | 90 profile_ = browser->profile(); |
91 observer_.reset(new ExtensionsServiceObserverBridge(self, profile_)); | |
92 ExtensionsService* extensionsService = profile_->GetExtensionsService(); | |
93 if (!extensionsService) { // |extensionsService| can be NULL in Incognito. | |
Erik does not do reviews
2010/02/10 16:57:41
FYI, this is going to change soon (see http://code
| |
94 toolbarModel_ = NULL; | |
95 } else { | |
96 toolbarModel_ = extensionsService->toolbar_model(); | |
97 toolbarModel_->AddObserver(observer_.get()); | |
98 } | |
100 | 99 |
101 containerView_ = container; | 100 containerView_ = container; |
102 [containerView_ setHidden:YES]; | 101 [containerView_ setHidden:YES]; |
103 observer_.reset(new ExtensionsServiceObserverBridge(self, profile_)); | 102 |
104 buttons_.reset([[NSMutableDictionary alloc] init]); | 103 buttons_.reset([[NSMutableDictionary alloc] init]); |
105 buttonOrder_.reset([[NSMutableArray alloc] init]); | 104 buttonOrder_.reset([[NSMutableArray alloc] init]); |
106 } | 105 } |
107 | 106 |
108 return self; | 107 return self; |
109 } | 108 } |
110 | 109 |
111 - (void)dealloc { | 110 - (void)dealloc { |
111 if (toolbarModel_) | |
112 toolbarModel_->RemoveObserver(observer_.get()); | |
113 | |
112 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 114 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
113 [super dealloc]; | 115 [super dealloc]; |
114 } | 116 } |
115 | 117 |
116 - (void)update { | 118 - (void)update { |
117 for (BrowserActionButton* button in [buttons_ allValues]) { | 119 for (BrowserActionButton* button in [buttons_ allValues]) { |
118 [button setTabId:[self currentTabId]]; | 120 [button setTabId:[self currentTabId]]; |
119 [button updateState]; | 121 [button updateState]; |
120 } | 122 } |
121 } | 123 } |
122 | 124 |
123 - (void)browserActionVisibilityHasChanged { | |
124 [containerView_ setNeedsDisplay:YES]; | |
125 } | |
126 | |
127 - (void)createButtons { | 125 - (void)createButtons { |
128 ExtensionsService* extensionsService = profile_->GetExtensionsService(); | 126 // No extensions in incognito mode. |
129 if (!extensionsService) // |extensionsService| can be NULL in Incognito. | 127 if (!toolbarModel_) |
130 return; | 128 return; |
131 | 129 |
132 for (size_t i = 0; i < extensionsService->extensions()->size(); ++i) { | 130 int i = 0; |
133 Extension* extension = extensionsService->GetExtensionById( | 131 for (ExtensionList::iterator iter = toolbarModel_->begin(); |
134 extensionsService->extensions()->at(i)->id(), false); | 132 iter != toolbarModel_->end(); ++iter) { |
135 if (extension->browser_action()) { | 133 [self createActionButtonForExtension:*iter withIndex:i++]; |
136 [self createActionButtonForExtension:extension]; | |
137 } | |
138 } | 134 } |
139 } | 135 } |
140 | 136 |
141 - (void)createActionButtonForExtension:(Extension*)extension { | 137 - (void)createActionButtonForExtension:(Extension*)extension |
138 withIndex:(int)index { | |
142 if (!extension->browser_action()) | 139 if (!extension->browser_action()) |
143 return; | 140 return; |
144 | 141 |
145 if ([buttons_ count] == 0) { | 142 // Show the container if it's the first button. Otherwise it will be shown |
146 // Only call if we're adding our first button, otherwise it will be shown | 143 // already. |
147 // already. | 144 if ([buttons_ count] == 0) |
148 [containerView_ setHidden:NO]; | 145 [containerView_ setHidden:NO]; |
149 } | |
150 | 146 |
151 int xOffset = | 147 BrowserActionButton* newButton = [[[BrowserActionButton alloc] |
152 [buttons_ count] * (kBrowserActionWidth + kBrowserActionButtonPadding); | 148 initWithExtension:extension |
153 BrowserActionButton* newButton = | 149 profile:profile_ |
154 [[[BrowserActionButton alloc] initWithExtension:extension | 150 tabId:[self currentTabId]] autorelease]; |
155 tabId:[self currentTabId] | |
156 xOffset:xOffset] autorelease]; | |
157 [newButton setTarget:self]; | 151 [newButton setTarget:self]; |
158 [newButton setAction:@selector(browserActionClicked:)]; | 152 [newButton setAction:@selector(browserActionClicked:)]; |
159 NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); | 153 NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); |
160 [buttons_ setObject:newButton forKey:buttonKey]; | 154 [buttons_ setObject:newButton forKey:buttonKey]; |
161 [buttonOrder_ addObject:newButton]; | 155 [buttonOrder_ insertObject:newButton atIndex:index]; |
162 [containerView_ addSubview:newButton]; | 156 [containerView_ addSubview:newButton]; |
157 [self repositionActionButtons]; | |
163 | 158 |
164 [[NSNotificationCenter defaultCenter] | 159 [[NSNotificationCenter defaultCenter] |
165 postNotificationName:kBrowserActionsChangedNotification object:self]; | 160 postNotificationName:kBrowserActionsChangedNotification object:self]; |
161 [containerView_ setNeedsDisplay:YES]; | |
Erik does not do reviews
2010/02/10 16:57:41
I thought adding and removing subviews always set
Bons
2010/02/10 17:52:30
I don't see anything in the docs, but also, we wan
| |
166 } | 162 } |
167 | 163 |
168 - (void)removeActionButtonForExtension:(Extension*)extension { | 164 - (void)removeActionButtonForExtension:(Extension*)extension { |
169 if (!extension->browser_action()) | 165 if (!extension->browser_action()) |
170 return; | 166 return; |
171 | 167 |
172 NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); | 168 NSString* buttonKey = base::SysUTF8ToNSString(extension->id()); |
173 | 169 |
174 BrowserActionButton* button = [buttons_ objectForKey:buttonKey]; | 170 BrowserActionButton* button = [buttons_ objectForKey:buttonKey]; |
175 if (!button) { | 171 if (!button) { |
176 NOTREACHED(); | 172 NOTREACHED(); |
177 return; | 173 return; |
178 } | 174 } |
179 [button removeFromSuperview]; | 175 [button removeFromSuperview]; |
180 [buttons_ removeObjectForKey:buttonKey]; | 176 [buttons_ removeObjectForKey:buttonKey]; |
181 [buttonOrder_ removeObject:button]; | 177 [buttonOrder_ removeObject:button]; |
182 if ([buttons_ count] == 0) { | 178 if ([buttons_ count] == 0) { |
183 // No more buttons? Hide the container. | 179 // No more buttons? Hide the container. |
184 [containerView_ setHidden:YES]; | 180 [containerView_ setHidden:YES]; |
185 } else { | 181 } else { |
186 // repositionActionButtons only needs to be called if removing a browser | |
187 // action button because adding one will always append to the end of the | |
188 // container, while removing one may require that those to the right of it | |
189 // be shifted to the left. | |
190 [self repositionActionButtons]; | 182 [self repositionActionButtons]; |
191 } | 183 } |
192 [[NSNotificationCenter defaultCenter] | 184 [[NSNotificationCenter defaultCenter] |
193 postNotificationName:kBrowserActionsChangedNotification object:self]; | 185 postNotificationName:kBrowserActionsChangedNotification object:self]; |
186 [containerView_ setNeedsDisplay:YES]; | |
194 } | 187 } |
195 | 188 |
196 - (void)repositionActionButtons { | 189 - (void)repositionActionButtons { |
197 for (NSUInteger i = 0; i < [buttonOrder_ count]; ++i) { | 190 for (NSUInteger i = 0; i < [buttonOrder_ count]; ++i) { |
198 CGFloat xOffset = i * (kBrowserActionWidth + kBrowserActionButtonPadding); | 191 CGFloat xOffset = i * (kBrowserActionWidth + kBrowserActionButtonPadding); |
199 BrowserActionButton* button = [buttonOrder_ objectAtIndex:i]; | 192 BrowserActionButton* button = [buttonOrder_ objectAtIndex:i]; |
200 NSRect buttonFrame = [button frame]; | 193 NSRect buttonFrame = [button frame]; |
201 buttonFrame.origin.x = xOffset; | 194 buttonFrame.origin.x = xOffset; |
202 [button setFrame:buttonFrame]; | 195 [button setFrame:buttonFrame]; |
203 } | 196 } |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
267 } | 260 } |
268 NOTREACHED(); | 261 NOTREACHED(); |
269 return nil; | 262 return nil; |
270 } | 263 } |
271 | 264 |
272 - (NSButton*)buttonWithIndex:(int)index { | 265 - (NSButton*)buttonWithIndex:(int)index { |
273 return [buttonOrder_ objectAtIndex:(NSUInteger)index]; | 266 return [buttonOrder_ objectAtIndex:(NSUInteger)index]; |
274 } | 267 } |
275 | 268 |
276 @end | 269 @end |
OLD | NEW |