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 #include "chrome/browser/extensions/extension_menu_manager.h" | 5 #include "chrome/browser/extensions/extension_menu_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 // added. | 132 // added. |
133 if (extension_id.empty() || ContainsKey(items_by_id_, item->id())) | 133 if (extension_id.empty() || ContainsKey(items_by_id_, item->id())) |
134 return false; | 134 return false; |
135 | 135 |
136 DCHECK_EQ(extension->id(), extension_id); | 136 DCHECK_EQ(extension->id(), extension_id); |
137 | 137 |
138 bool first_item = !ContainsKey(context_items_, extension_id); | 138 bool first_item = !ContainsKey(context_items_, extension_id); |
139 context_items_[extension_id].push_back(item); | 139 context_items_[extension_id].push_back(item); |
140 items_by_id_[item->id()] = item; | 140 items_by_id_[item->id()] = item; |
141 | 141 |
142 if (item->type() == ExtensionMenuItem::RADIO && item->checked()) | 142 if (item->type() == ExtensionMenuItem::RADIO) { |
143 RadioItemSelected(item); | 143 if (item->checked()) |
| 144 RadioItemSelected(item); |
| 145 else |
| 146 SanitizeRadioList(context_items_[extension_id]); |
| 147 } |
144 | 148 |
145 // If this is the first item for this extension, start loading its icon. | 149 // If this is the first item for this extension, start loading its icon. |
146 if (first_item) | 150 if (first_item) |
147 icon_manager_.LoadIcon(extension); | 151 icon_manager_.LoadIcon(extension); |
148 | 152 |
149 return true; | 153 return true; |
150 } | 154 } |
151 | 155 |
152 bool ExtensionMenuManager::AddChildItem(const ExtensionMenuItem::Id& parent_id, | 156 bool ExtensionMenuManager::AddChildItem(const ExtensionMenuItem::Id& parent_id, |
153 ExtensionMenuItem* child) { | 157 ExtensionMenuItem* child) { |
154 ExtensionMenuItem* parent = GetItemById(parent_id); | 158 ExtensionMenuItem* parent = GetItemById(parent_id); |
155 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || | 159 if (!parent || parent->type() != ExtensionMenuItem::NORMAL || |
156 parent->extension_id() != child->extension_id() || | 160 parent->extension_id() != child->extension_id() || |
157 ContainsKey(items_by_id_, child->id())) | 161 ContainsKey(items_by_id_, child->id())) |
158 return false; | 162 return false; |
159 parent->AddChild(child); | 163 parent->AddChild(child); |
160 items_by_id_[child->id()] = child; | 164 items_by_id_[child->id()] = child; |
| 165 |
| 166 if (child->type() == ExtensionMenuItem::RADIO) |
| 167 SanitizeRadioList(parent->children()); |
| 168 |
161 return true; | 169 return true; |
162 } | 170 } |
163 | 171 |
164 bool ExtensionMenuManager::DescendantOf( | 172 bool ExtensionMenuManager::DescendantOf( |
165 ExtensionMenuItem* item, | 173 ExtensionMenuItem* item, |
166 const ExtensionMenuItem::Id& ancestor_id) { | 174 const ExtensionMenuItem::Id& ancestor_id) { |
167 // Work our way up the tree until we find the ancestor or NULL. | 175 // Work our way up the tree until we find the ancestor or NULL. |
168 ExtensionMenuItem::Id* id = item->parent_id(); | 176 ExtensionMenuItem::Id* id = item->parent_id(); |
169 while (id != NULL) { | 177 while (id != NULL) { |
170 DCHECK(*id != item->id()); // Catch circular graphs. | 178 DCHECK(*id != item->id()); // Catch circular graphs. |
(...skipping 23 matching lines...) Expand all Loading... |
194 ExtensionMenuItem::Id* old_parent_id = child->parent_id(); | 202 ExtensionMenuItem::Id* old_parent_id = child->parent_id(); |
195 if (old_parent_id != NULL) { | 203 if (old_parent_id != NULL) { |
196 ExtensionMenuItem* old_parent = GetItemById(*old_parent_id); | 204 ExtensionMenuItem* old_parent = GetItemById(*old_parent_id); |
197 if (!old_parent) { | 205 if (!old_parent) { |
198 NOTREACHED(); | 206 NOTREACHED(); |
199 return false; | 207 return false; |
200 } | 208 } |
201 ExtensionMenuItem* taken = | 209 ExtensionMenuItem* taken = |
202 old_parent->ReleaseChild(child_id, false /* non-recursive search*/); | 210 old_parent->ReleaseChild(child_id, false /* non-recursive search*/); |
203 DCHECK(taken == child); | 211 DCHECK(taken == child); |
| 212 SanitizeRadioList(old_parent->children()); |
204 } else { | 213 } else { |
205 // This is a top-level item, so we need to pull it out of our list of | 214 // This is a top-level item, so we need to pull it out of our list of |
206 // top-level items. | 215 // top-level items. |
207 MenuItemMap::iterator i = context_items_.find(child->extension_id()); | 216 MenuItemMap::iterator i = context_items_.find(child->extension_id()); |
208 if (i == context_items_.end()) { | 217 if (i == context_items_.end()) { |
209 NOTREACHED(); | 218 NOTREACHED(); |
210 return false; | 219 return false; |
211 } | 220 } |
212 ExtensionMenuItem::List& list = i->second; | 221 ExtensionMenuItem::List& list = i->second; |
213 ExtensionMenuItem::List::iterator j = std::find(list.begin(), list.end(), | 222 ExtensionMenuItem::List::iterator j = std::find(list.begin(), list.end(), |
214 child); | 223 child); |
215 if (j == list.end()) { | 224 if (j == list.end()) { |
216 NOTREACHED(); | 225 NOTREACHED(); |
217 return false; | 226 return false; |
218 } | 227 } |
219 list.erase(j); | 228 list.erase(j); |
| 229 SanitizeRadioList(list); |
220 } | 230 } |
221 | 231 |
222 if (new_parent) { | 232 if (new_parent) { |
223 new_parent->AddChild(child); | 233 new_parent->AddChild(child); |
| 234 SanitizeRadioList(new_parent->children()); |
224 } else { | 235 } else { |
225 context_items_[child->extension_id()].push_back(child); | 236 context_items_[child->extension_id()].push_back(child); |
226 child->parent_id_.reset(NULL); | 237 child->parent_id_.reset(NULL); |
| 238 SanitizeRadioList(context_items_[child->extension_id()]); |
227 } | 239 } |
228 return true; | 240 return true; |
229 } | 241 } |
230 | 242 |
231 bool ExtensionMenuManager::RemoveContextMenuItem( | 243 bool ExtensionMenuManager::RemoveContextMenuItem( |
232 const ExtensionMenuItem::Id& id) { | 244 const ExtensionMenuItem::Id& id) { |
233 if (!ContainsKey(items_by_id_, id)) | 245 if (!ContainsKey(items_by_id_, id)) |
234 return false; | 246 return false; |
235 | 247 |
236 ExtensionMenuItem* menu_item = GetItemById(id); | 248 ExtensionMenuItem* menu_item = GetItemById(id); |
(...skipping 10 matching lines...) Expand all Loading... |
247 ExtensionMenuItem::List& list = i->second; | 259 ExtensionMenuItem::List& list = i->second; |
248 ExtensionMenuItem::List::iterator j; | 260 ExtensionMenuItem::List::iterator j; |
249 for (j = list.begin(); j < list.end(); ++j) { | 261 for (j = list.begin(); j < list.end(); ++j) { |
250 // See if the current top-level item is a match. | 262 // See if the current top-level item is a match. |
251 if ((*j)->id() == id) { | 263 if ((*j)->id() == id) { |
252 items_removed = (*j)->RemoveAllDescendants(); | 264 items_removed = (*j)->RemoveAllDescendants(); |
253 items_removed.insert(id); | 265 items_removed.insert(id); |
254 delete *j; | 266 delete *j; |
255 list.erase(j); | 267 list.erase(j); |
256 result = true; | 268 result = true; |
| 269 SanitizeRadioList(list); |
257 break; | 270 break; |
258 } else { | 271 } else { |
259 // See if the item to remove was found as a descendant of the current | 272 // See if the item to remove was found as a descendant of the current |
260 // top-level item. | 273 // top-level item. |
261 ExtensionMenuItem* child = (*j)->ReleaseChild(id, true /* recursive */); | 274 ExtensionMenuItem* child = (*j)->ReleaseChild(id, true /* recursive */); |
262 if (child) { | 275 if (child) { |
263 items_removed = child->RemoveAllDescendants(); | 276 items_removed = child->RemoveAllDescendants(); |
264 items_removed.insert(id); | 277 items_removed.insert(id); |
| 278 SanitizeRadioList(GetItemById(*child->parent_id())->children()); |
265 delete child; | 279 delete child; |
266 result = true; | 280 result = true; |
267 break; | 281 break; |
268 } | 282 } |
269 } | 283 } |
270 } | 284 } |
271 DCHECK(result); // The check at the very top should have prevented this. | 285 DCHECK(result); // The check at the very top should have prevented this. |
272 | 286 |
273 // Clear entries from the items_by_id_ map. | 287 // Clear entries from the items_by_id_ map. |
274 std::set<ExtensionMenuItem::Id>::iterator removed_iter; | 288 std::set<ExtensionMenuItem::Id>::iterator removed_iter; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 properties->SetBoolean("checked", item->checked()); | 456 properties->SetBoolean("checked", item->checked()); |
443 } | 457 } |
444 | 458 |
445 std::string json_args; | 459 std::string json_args; |
446 base::JSONWriter::Write(&args, false, &json_args); | 460 base::JSONWriter::Write(&args, false, &json_args); |
447 std::string event_name = "contextMenus"; | 461 std::string event_name = "contextMenus"; |
448 event_router->DispatchEventToExtension( | 462 event_router->DispatchEventToExtension( |
449 item->extension_id(), event_name, json_args, profile, GURL()); | 463 item->extension_id(), event_name, json_args, profile, GURL()); |
450 } | 464 } |
451 | 465 |
| 466 void ExtensionMenuManager::SanitizeRadioList( |
| 467 const ExtensionMenuItem::List& item_list) { |
| 468 ExtensionMenuItem::List::const_iterator i = item_list.begin(); |
| 469 while (i != item_list.end()) { |
| 470 if ((*i)->type() != ExtensionMenuItem::RADIO) { |
| 471 ++i; |
| 472 break; |
| 473 } |
| 474 |
| 475 // Uncheck any checked radio items in the run, and at the end reset |
| 476 // the appropriate one to checked. If no check radio items were found, |
| 477 // then check the first radio item in the run. |
| 478 ExtensionMenuItem::List::const_iterator last_checked = item_list.end(); |
| 479 ExtensionMenuItem::List::const_iterator radio_run_iter; |
| 480 for (radio_run_iter = i; radio_run_iter != item_list.end(); |
| 481 ++radio_run_iter) { |
| 482 if ((*radio_run_iter)->type() != ExtensionMenuItem::RADIO) { |
| 483 break; |
| 484 } |
| 485 |
| 486 if ((*radio_run_iter)->checked()) { |
| 487 last_checked = radio_run_iter; |
| 488 (*radio_run_iter)->SetChecked(false); |
| 489 } |
| 490 } |
| 491 |
| 492 if (last_checked != item_list.end()) |
| 493 (*last_checked)->SetChecked(true); |
| 494 else |
| 495 (*i)->SetChecked(true); |
| 496 |
| 497 i = radio_run_iter; |
| 498 } |
| 499 } |
| 500 |
| 501 bool ExtensionMenuManager::ItemUpdated(const ExtensionMenuItem::Id& id) { |
| 502 if (!ContainsKey(items_by_id_, id)) |
| 503 return false; |
| 504 |
| 505 ExtensionMenuItem* menu_item = GetItemById(id); |
| 506 DCHECK(menu_item); |
| 507 |
| 508 if (menu_item->parent_id()) { |
| 509 SanitizeRadioList(GetItemById(*menu_item->parent_id())->children()); |
| 510 } else { |
| 511 std::string extension_id = menu_item->extension_id(); |
| 512 MenuItemMap::iterator i = context_items_.find(extension_id); |
| 513 if (i == context_items_.end()) { |
| 514 NOTREACHED(); |
| 515 return false; |
| 516 } |
| 517 SanitizeRadioList(i->second); |
| 518 } |
| 519 |
| 520 return true; |
| 521 } |
| 522 |
452 void ExtensionMenuManager::Observe( | 523 void ExtensionMenuManager::Observe( |
453 int type, | 524 int type, |
454 const content::NotificationSource& source, | 525 const content::NotificationSource& source, |
455 const content::NotificationDetails& details) { | 526 const content::NotificationDetails& details) { |
456 DCHECK(type == chrome::NOTIFICATION_EXTENSION_UNLOADED); | 527 DCHECK(type == chrome::NOTIFICATION_EXTENSION_UNLOADED); |
457 | 528 |
458 // Remove menu items for disabled/uninstalled extensions. | 529 // Remove menu items for disabled/uninstalled extensions. |
459 const Extension* extension = | 530 const Extension* extension = |
460 content::Details<UnloadedExtensionInfo>(details)->extension; | 531 content::Details<UnloadedExtensionInfo>(details)->extension; |
461 if (ContainsKey(context_items_, extension->id())) { | 532 if (ContainsKey(context_items_, extension->id())) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 if (profile < other.profile) | 566 if (profile < other.profile) |
496 return true; | 567 return true; |
497 if (profile == other.profile) { | 568 if (profile == other.profile) { |
498 if (extension_id < other.extension_id) | 569 if (extension_id < other.extension_id) |
499 return true; | 570 return true; |
500 if (extension_id == other.extension_id) | 571 if (extension_id == other.extension_id) |
501 return uid < other.uid; | 572 return uid < other.uid; |
502 } | 573 } |
503 return false; | 574 return false; |
504 } | 575 } |
OLD | NEW |