OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/extensions/extension_shelf_model.h" | |
6 | |
7 #include "base/stl_util-inl.h" | |
8 #include "chrome/browser/browser.h" | |
9 #include "chrome/browser/profile.h" | |
10 #include "chrome/browser/extensions/extension_host.h" | |
11 #include "chrome/browser/extensions/extension_process_manager.h" | |
12 #include "chrome/browser/extensions/extension_toolstrip_api.h" | |
13 #include "chrome/browser/extensions/extensions_service.h" | |
14 #include "chrome/browser/renderer_host/render_view_host.h" | |
15 #include "chrome/common/extensions/extension.h" | |
16 #include "chrome/common/notification_service.h" | |
17 | |
18 ExtensionShelfModel::ExtensionShelfModel(Browser* browser) | |
19 : browser_(browser), ready_(false) { | |
20 // Watch extensions loaded and unloaded notifications. | |
21 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | |
22 NotificationService::AllSources()); | |
23 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | |
24 NotificationService::AllSources()); | |
25 registrar_.Add(this, NotificationType::EXTENSIONS_READY, | |
26 NotificationService::AllSources()); | |
27 | |
28 // Add any already-loaded extensions now, since we missed the notification for | |
29 // those. | |
30 ExtensionsService* service = browser_->profile()->GetExtensionsService(); | |
31 if (service) { // This can be null in unit tests. | |
32 prefs_ = browser_->profile()->GetExtensionsService()->extension_prefs(); | |
33 registrar_.Add(this, NotificationType::EXTENSION_SHELF_MODEL_CHANGED, | |
34 Source<ExtensionPrefs>(prefs_)); | |
35 ready_ = service->is_ready(); | |
36 if (ready_) { | |
37 AddExtensions(service->extensions()); | |
38 SortToolstrips(); | |
39 } | |
40 } | |
41 } | |
42 | |
43 ExtensionShelfModel::~ExtensionShelfModel() { | |
44 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
45 ShelfModelDeleting()); | |
46 | |
47 observers_.Clear(); | |
48 | |
49 for (iterator t = toolstrips_.begin(); t != toolstrips_.end(); ++t) | |
50 delete t->host; | |
51 toolstrips_.clear(); | |
52 } | |
53 | |
54 void ExtensionShelfModel::AddObserver(ExtensionShelfModelObserver* observer) { | |
55 observers_.AddObserver(observer); | |
56 } | |
57 | |
58 void ExtensionShelfModel::RemoveObserver( | |
59 ExtensionShelfModelObserver* observer) { | |
60 observers_.RemoveObserver(observer); | |
61 } | |
62 | |
63 void ExtensionShelfModel::AppendToolstrip(const ToolstripItem& toolstrip) { | |
64 InsertToolstripAt(count(), toolstrip); | |
65 } | |
66 | |
67 void ExtensionShelfModel::InsertToolstripAt(int index, | |
68 const ToolstripItem& toolstrip) { | |
69 toolstrips_.insert(toolstrips_.begin() + index, toolstrip); | |
70 if (ready_) { | |
71 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
72 ToolstripInsertedAt(toolstrip.host, index)); | |
73 } | |
74 } | |
75 | |
76 void ExtensionShelfModel::RemoveToolstripAt(int index) { | |
77 ExtensionHost* host = ToolstripAt(index).host; | |
78 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
79 ToolstripRemovingAt(host, index)); | |
80 toolstrips_.erase(toolstrips_.begin() + index); | |
81 delete host; | |
82 } | |
83 | |
84 void ExtensionShelfModel::MoveToolstripAt(int index, int to_index) { | |
85 DCHECK(index >= 0); | |
86 DCHECK(to_index >= 0); | |
87 if (index == to_index) | |
88 return; | |
89 | |
90 ToolstripItem toolstrip = toolstrips_[index]; | |
91 toolstrips_.erase(toolstrips_.begin() + index); | |
92 toolstrips_.insert(toolstrips_.begin() + to_index, toolstrip); | |
93 | |
94 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
95 ToolstripMoved(toolstrip.host, index, to_index)); | |
96 | |
97 UpdatePrefs(); | |
98 } | |
99 | |
100 int ExtensionShelfModel::IndexOfHost(ExtensionHost* host) { | |
101 for (iterator i = toolstrips_.begin(); i != toolstrips_.end(); ++i) { | |
102 if (i->host == host) | |
103 return i - toolstrips_.begin(); | |
104 } | |
105 return -1; | |
106 } | |
107 | |
108 ExtensionShelfModel::iterator ExtensionShelfModel::ToolstripForHost( | |
109 ExtensionHost* host) { | |
110 for (iterator i = toolstrips_.begin(); i != toolstrips_.end(); ++i) { | |
111 if (i->host == host) | |
112 return i; | |
113 } | |
114 return toolstrips_.end(); | |
115 } | |
116 | |
117 const ExtensionShelfModel::ToolstripItem& ExtensionShelfModel::ToolstripAt( | |
118 int index) { | |
119 DCHECK(index >= 0); | |
120 return toolstrips_[index]; | |
121 } | |
122 | |
123 void ExtensionShelfModel::SetToolstripDataAt(int index, void* data) { | |
124 DCHECK(index >= 0); | |
125 toolstrips_[index].data = data; | |
126 } | |
127 | |
128 void ExtensionShelfModel::ExpandToolstrip(iterator toolstrip, | |
129 const GURL& url, int height) { | |
130 if (toolstrip == end()) | |
131 return; | |
132 toolstrip->height = height; | |
133 toolstrip->url = url; | |
134 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
135 ToolstripChanged(toolstrip)); | |
136 int routing_id = toolstrip->host->render_view_host()->routing_id(); | |
137 ToolstripEventRouter::OnToolstripExpanded(browser_->profile(), | |
138 routing_id, | |
139 url, height); | |
140 toolstrip->host->SetRenderViewType(ViewType::EXTENSION_MOLE); | |
141 } | |
142 | |
143 void ExtensionShelfModel::CollapseToolstrip(iterator toolstrip, | |
144 const GURL& url) { | |
145 if (toolstrip == end()) | |
146 return; | |
147 toolstrip->height = 0; | |
148 toolstrip->url = url; | |
149 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
150 ToolstripChanged(toolstrip)); | |
151 int routing_id = toolstrip->host->render_view_host()->routing_id(); | |
152 ToolstripEventRouter::OnToolstripCollapsed(browser_->profile(), | |
153 routing_id, | |
154 url); | |
155 toolstrip->host->SetRenderViewType(ViewType::EXTENSION_TOOLSTRIP); | |
156 } | |
157 | |
158 void ExtensionShelfModel::Observe(NotificationType type, | |
159 const NotificationSource& source, | |
160 const NotificationDetails& details) { | |
161 switch (type.value) { | |
162 case NotificationType::EXTENSION_LOADED: | |
163 if (ready_) | |
164 AddExtension(Details<Extension>(details).ptr()); | |
165 break; | |
166 case NotificationType::EXTENSION_UNLOADED: | |
167 RemoveExtension(Details<Extension>(details).ptr()); | |
168 break; | |
169 case NotificationType::EXTENSIONS_READY: | |
170 if (browser_->profile()->GetExtensionsService()) { | |
171 AddExtensions( | |
172 browser_->profile()->GetExtensionsService()->extensions()); | |
173 SortToolstrips(); | |
174 } | |
175 ready_ = true; | |
176 break; | |
177 case NotificationType::EXTENSION_SHELF_MODEL_CHANGED: | |
178 // Ignore changes that this model originated. | |
179 if (Details<ExtensionShelfModel>(details).ptr() != this) | |
180 SortToolstrips(); | |
181 break; | |
182 default: | |
183 DCHECK(false) << "Unhandled notification of type: " << type.value; | |
184 break; | |
185 } | |
186 } | |
187 | |
188 void ExtensionShelfModel::AddExtension(Extension* extension) { | |
189 ExtensionProcessManager* manager = | |
190 browser_->profile()->GetExtensionProcessManager(); | |
191 DCHECK(manager); | |
192 if (!manager) | |
193 return; | |
194 | |
195 for (std::vector<Extension::ToolstripInfo>::const_iterator toolstrip = | |
196 extension->toolstrips().begin(); | |
197 toolstrip != extension->toolstrips().end(); ++toolstrip) { | |
198 GURL url = toolstrip->toolstrip; | |
199 ToolstripItem item; | |
200 item.host = manager->CreateToolstrip(extension, url, browser_); | |
201 item.info = *toolstrip; | |
202 item.data = NULL; | |
203 item.height = 0; | |
204 AppendToolstrip(item); | |
205 } | |
206 } | |
207 | |
208 void ExtensionShelfModel::AddExtensions(const ExtensionList* extensions) { | |
209 if (extensions->size()) { | |
210 ExtensionList::const_iterator extension = extensions->begin(); | |
211 for (; extension != extensions->end(); ++extension) | |
212 AddExtension(*extension); | |
213 } | |
214 } | |
215 | |
216 void ExtensionShelfModel::RemoveExtension(Extension* extension) { | |
217 bool changed = false; | |
218 for (int i = count() - 1; i >= 0; --i) { | |
219 ExtensionHost* t = ToolstripAt(i).host; | |
220 if (t->extension()->id() == extension->id()) { | |
221 changed = true; | |
222 RemoveToolstripAt(i); | |
223 | |
224 // There can be more than one toolstrip per extension, so we have to keep | |
225 // looping even after finding a match. | |
226 } | |
227 } | |
228 if (changed) | |
229 UpdatePrefs(); | |
230 } | |
231 | |
232 void ExtensionShelfModel::UpdatePrefs() { | |
233 if (!prefs_) | |
234 return; | |
235 | |
236 // It's easiest to just rebuild the list each time. | |
237 ExtensionPrefs::URLList urls; | |
238 for (int i = 0; i < count(); ++i) | |
239 urls.push_back(ToolstripAt(i).host->GetURL()); | |
240 prefs_->SetShelfToolstripOrder(urls); | |
241 | |
242 NotificationService::current()->Notify( | |
243 NotificationType::EXTENSION_SHELF_MODEL_CHANGED, | |
244 Source<ExtensionPrefs>(prefs_), | |
245 Details<ExtensionShelfModel>(this)); | |
246 } | |
247 | |
248 void ExtensionShelfModel::SortToolstrips() { | |
249 ExtensionPrefs::URLList urls = prefs_->GetShelfToolstripOrder(); | |
250 ToolstripList copy = | |
251 ToolstripList(toolstrips_.begin(), toolstrips_.end()); | |
252 toolstrips_.clear(); | |
253 | |
254 // Go through the urls and find the matching toolstrip, re-adding it to the | |
255 // new list in the proper order. | |
256 for (size_t i = 0; i < urls.size(); ++i) { | |
257 GURL& url = urls[i]; | |
258 for (iterator toolstrip = copy.begin(); | |
259 toolstrip != copy.end(); ++toolstrip) { | |
260 if (url == toolstrip->host->GetURL()) { | |
261 // Note that it's technically possible for the same URL to appear in | |
262 // multiple toolstrips, so we don't do any testing for uniqueness. | |
263 toolstrips_.push_back(*toolstrip); | |
264 | |
265 // Remove the toolstrip from the list so we don't have to iterate over | |
266 // it next time. | |
267 copy.erase(toolstrip); | |
268 break; | |
269 } | |
270 } | |
271 } | |
272 | |
273 // Any toolstrips remaining in |copy| were somehow missing from the prefs, | |
274 // so just append them to the end. | |
275 for (iterator toolstrip = copy.begin(); | |
276 toolstrip != copy.end(); ++toolstrip) { | |
277 toolstrips_.push_back(*toolstrip); | |
278 } | |
279 | |
280 FOR_EACH_OBSERVER(ExtensionShelfModelObserver, observers_, | |
281 ShelfModelReloaded()); | |
282 } | |
OLD | NEW |