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