OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/menu_manager.h" | 5 #include "chrome/browser/extensions/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" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 #include "chrome/browser/chrome_notification_types.h" | 15 #include "chrome/browser/chrome_notification_types.h" |
16 #include "chrome/browser/extensions/event_names.h" | 16 #include "chrome/browser/extensions/event_names.h" |
17 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
18 #include "chrome/browser/extensions/extension_tab_util.h" | 18 #include "chrome/browser/extensions/extension_tab_util.h" |
19 #include "chrome/browser/extensions/menu_manager_factory.h" | 19 #include "chrome/browser/extensions/menu_manager_factory.h" |
20 #include "chrome/browser/extensions/state_store.h" | 20 #include "chrome/browser/extensions/state_store.h" |
21 #include "chrome/browser/extensions/tab_helper.h" | 21 #include "chrome/browser/extensions/tab_helper.h" |
22 #include "chrome/browser/guestview/webview/webview_guest.h" | |
22 #include "chrome/browser/profiles/profile.h" | 23 #include "chrome/browser/profiles/profile.h" |
23 #include "chrome/common/extensions/api/context_menus.h" | 24 #include "chrome/common/extensions/api/context_menus.h" |
24 #include "content/public/browser/notification_details.h" | 25 #include "content/public/browser/notification_details.h" |
25 #include "content/public/browser/notification_service.h" | 26 #include "content/public/browser/notification_service.h" |
26 #include "content/public/browser/notification_source.h" | 27 #include "content/public/browser/notification_source.h" |
27 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
28 #include "content/public/common/context_menu_params.h" | 29 #include "content/public/common/context_menu_params.h" |
29 #include "extensions/browser/event_router.h" | 30 #include "extensions/browser/event_router.h" |
30 #include "extensions/browser/extension_system.h" | 31 #include "extensions/browser/extension_system.h" |
31 #include "extensions/common/extension.h" | 32 #include "extensions/common/extension.h" |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
215 return value.Pass(); | 216 return value.Pass(); |
216 } | 217 } |
217 | 218 |
218 // static | 219 // static |
219 MenuItem* MenuItem::Populate(const std::string& extension_id, | 220 MenuItem* MenuItem::Populate(const std::string& extension_id, |
220 const base::DictionaryValue& value, | 221 const base::DictionaryValue& value, |
221 std::string* error) { | 222 std::string* error) { |
222 bool incognito = false; | 223 bool incognito = false; |
223 if (!value.GetBoolean(kIncognitoKey, &incognito)) | 224 if (!value.GetBoolean(kIncognitoKey, &incognito)) |
224 return NULL; | 225 return NULL; |
225 Id id(incognito, extension_id); | 226 Id id(incognito, MenuItem::ExtensionKey(extension_id)); |
226 if (!value.GetString(kStringUIDKey, &id.string_uid)) | 227 if (!value.GetString(kStringUIDKey, &id.string_uid)) |
227 return NULL; | 228 return NULL; |
228 int type_int; | 229 int type_int; |
229 Type type = NORMAL; | 230 Type type = NORMAL; |
230 if (!value.GetInteger(kTypeKey, &type_int)) | 231 if (!value.GetInteger(kTypeKey, &type_int)) |
231 return NULL; | 232 return NULL; |
232 type = static_cast<Type>(type_int); | 233 type = static_cast<Type>(type_int); |
233 std::string title; | 234 std::string title; |
234 if (type != SEPARATOR && !value.GetString(kTitleKey, &title)) | 235 if (type != SEPARATOR && !value.GetString(kTitleKey, &title)) |
235 return NULL; | 236 return NULL; |
(...skipping 23 matching lines...) Expand all Loading... | |
259 return NULL; | 260 return NULL; |
260 | 261 |
261 if (!result->PopulateURLPatterns(&document_url_patterns, | 262 if (!result->PopulateURLPatterns(&document_url_patterns, |
262 &target_url_patterns, | 263 &target_url_patterns, |
263 error)) { | 264 error)) { |
264 return NULL; | 265 return NULL; |
265 } | 266 } |
266 | 267 |
267 // parent_id is filled in from the value, but it might not be valid. It's left | 268 // parent_id is filled in from the value, but it might not be valid. It's left |
268 // to be validated upon being added (via AddChildItem) to the menu manager. | 269 // to be validated upon being added (via AddChildItem) to the menu manager. |
269 scoped_ptr<Id> parent_id(new Id(incognito, extension_id)); | 270 scoped_ptr<Id> parent_id( |
271 new Id(incognito, MenuItem::ExtensionKey(extension_id))); | |
270 if (value.HasKey(kParentUIDKey)) { | 272 if (value.HasKey(kParentUIDKey)) { |
271 if (!value.GetString(kParentUIDKey, &parent_id->string_uid)) | 273 if (!value.GetString(kParentUIDKey, &parent_id->string_uid)) |
272 return NULL; | 274 return NULL; |
273 result->parent_id_.swap(parent_id); | 275 result->parent_id_.swap(parent_id); |
274 } | 276 } |
275 return result.release(); | 277 return result.release(); |
276 } | 278 } |
277 | 279 |
278 bool MenuItem::PopulateURLPatterns( | 280 bool MenuItem::PopulateURLPatterns( |
279 std::vector<std::string>* document_url_patterns, | 281 std::vector<std::string>* document_url_patterns, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
311 for (i = context_items_.begin(); i != context_items_.end(); ++i) { | 313 for (i = context_items_.begin(); i != context_items_.end(); ++i) { |
312 STLDeleteElements(&(i->second)); | 314 STLDeleteElements(&(i->second)); |
313 } | 315 } |
314 } | 316 } |
315 | 317 |
316 // static | 318 // static |
317 MenuManager* MenuManager::Get(Profile* profile) { | 319 MenuManager* MenuManager::Get(Profile* profile) { |
318 return MenuManagerFactory::GetForProfile(profile); | 320 return MenuManagerFactory::GetForProfile(profile); |
319 } | 321 } |
320 | 322 |
321 std::set<std::string> MenuManager::ExtensionIds() { | 323 std::set<MenuItem::ExtensionKey> MenuManager::ExtensionIds() { |
322 std::set<std::string> id_set; | 324 std::set<MenuItem::ExtensionKey> id_set; |
323 for (MenuItemMap::const_iterator i = context_items_.begin(); | 325 for (MenuItemMap::const_iterator i = context_items_.begin(); |
324 i != context_items_.end(); ++i) { | 326 i != context_items_.end(); ++i) { |
325 id_set.insert(i->first); | 327 id_set.insert(i->first); |
326 } | 328 } |
327 return id_set; | 329 return id_set; |
328 } | 330 } |
329 | 331 |
330 const MenuItem::List* MenuManager::MenuItems( | 332 const MenuItem::List* MenuManager::MenuItems( |
331 const std::string& extension_id) { | 333 const MenuItem::ExtensionKey& key) { |
332 MenuItemMap::iterator i = context_items_.find(extension_id); | 334 MenuItemMap::iterator i = context_items_.find(key); |
333 if (i != context_items_.end()) { | 335 if (i != context_items_.end()) { |
334 return &(i->second); | 336 return &(i->second); |
335 } | 337 } |
336 return NULL; | 338 return NULL; |
337 } | 339 } |
338 | 340 |
339 bool MenuManager::AddContextItem( | 341 bool MenuManager::AddContextItem(const Extension* extension, MenuItem* item) { |
340 const Extension* extension, | 342 const MenuItem::ExtensionKey& key = item->id().extension_key; |
341 MenuItem* item) { | |
342 const std::string& extension_id = item->extension_id(); | |
343 // The item must have a non-empty extension id, and not have already been | 343 // The item must have a non-empty extension id, and not have already been |
344 // added. | 344 // added. |
345 if (extension_id.empty() || ContainsKey(items_by_id_, item->id())) | 345 if (key.empty() || ContainsKey(items_by_id_, item->id())) |
346 return false; | 346 return false; |
347 | 347 |
348 DCHECK_EQ(extension->id(), extension_id); | 348 DCHECK_EQ(extension->id(), key.extension_id); |
349 | 349 |
350 bool first_item = !ContainsKey(context_items_, extension_id); | 350 bool first_item = !ContainsKey(context_items_, key); |
351 context_items_[extension_id].push_back(item); | 351 context_items_[key].push_back(item); |
352 items_by_id_[item->id()] = item; | 352 items_by_id_[item->id()] = item; |
353 | 353 |
354 if (item->type() == MenuItem::RADIO) { | 354 if (item->type() == MenuItem::RADIO) { |
355 if (item->checked()) | 355 if (item->checked()) |
356 RadioItemSelected(item); | 356 RadioItemSelected(item); |
357 else | 357 else |
358 SanitizeRadioList(context_items_[extension_id]); | 358 SanitizeRadioList(context_items_[key]); |
359 } | 359 } |
360 | 360 |
361 // If this is the first item for this extension, start loading its icon. | 361 // If this is the first item for this extension, start loading its icon. |
362 if (first_item) | 362 if (first_item) |
363 icon_manager_.LoadIcon(profile_, extension); | 363 icon_manager_.LoadIcon(profile_, extension); |
364 | 364 |
365 return true; | 365 return true; |
366 } | 366 } |
367 | 367 |
368 bool MenuManager::AddChildItem(const MenuItem::Id& parent_id, | 368 bool MenuManager::AddChildItem(const MenuItem::Id& parent_id, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
417 NOTREACHED(); | 417 NOTREACHED(); |
418 return false; | 418 return false; |
419 } | 419 } |
420 MenuItem* taken = | 420 MenuItem* taken = |
421 old_parent->ReleaseChild(child_id, false /* non-recursive search*/); | 421 old_parent->ReleaseChild(child_id, false /* non-recursive search*/); |
422 DCHECK(taken == child); | 422 DCHECK(taken == child); |
423 SanitizeRadioList(old_parent->children()); | 423 SanitizeRadioList(old_parent->children()); |
424 } else { | 424 } else { |
425 // This is a top-level item, so we need to pull it out of our list of | 425 // This is a top-level item, so we need to pull it out of our list of |
426 // top-level items. | 426 // top-level items. |
427 MenuItemMap::iterator i = context_items_.find(child->extension_id()); | 427 const MenuItem::ExtensionKey& child_key = child->id().extension_key; |
428 MenuItemMap::iterator i = context_items_.find(child_key); | |
428 if (i == context_items_.end()) { | 429 if (i == context_items_.end()) { |
429 NOTREACHED(); | 430 NOTREACHED(); |
430 return false; | 431 return false; |
431 } | 432 } |
432 MenuItem::List& list = i->second; | 433 MenuItem::List& list = i->second; |
433 MenuItem::List::iterator j = std::find(list.begin(), list.end(), | 434 MenuItem::List::iterator j = std::find(list.begin(), list.end(), child); |
434 child); | |
435 if (j == list.end()) { | 435 if (j == list.end()) { |
436 NOTREACHED(); | 436 NOTREACHED(); |
437 return false; | 437 return false; |
438 } | 438 } |
439 list.erase(j); | 439 list.erase(j); |
440 SanitizeRadioList(list); | 440 SanitizeRadioList(list); |
441 } | 441 } |
442 | 442 |
443 if (new_parent) { | 443 if (new_parent) { |
444 new_parent->AddChild(child); | 444 new_parent->AddChild(child); |
445 SanitizeRadioList(new_parent->children()); | 445 SanitizeRadioList(new_parent->children()); |
446 } else { | 446 } else { |
447 context_items_[child->extension_id()].push_back(child); | 447 const MenuItem::ExtensionKey& child_key = child->id().extension_key; |
448 context_items_[child_key].push_back(child); | |
448 child->parent_id_.reset(NULL); | 449 child->parent_id_.reset(NULL); |
449 SanitizeRadioList(context_items_[child->extension_id()]); | 450 SanitizeRadioList(context_items_[child_key]); |
450 } | 451 } |
451 return true; | 452 return true; |
452 } | 453 } |
453 | 454 |
454 bool MenuManager::RemoveContextMenuItem(const MenuItem::Id& id) { | 455 bool MenuManager::RemoveContextMenuItem(const MenuItem::Id& id) { |
455 if (!ContainsKey(items_by_id_, id)) | 456 if (!ContainsKey(items_by_id_, id)) |
456 return false; | 457 return false; |
457 | 458 |
458 MenuItem* menu_item = GetItemById(id); | 459 MenuItem* menu_item = GetItemById(id); |
459 DCHECK(menu_item); | 460 DCHECK(menu_item); |
460 std::string extension_id = menu_item->extension_id(); | 461 MenuItemMap::iterator i = context_items_.find(id.extension_key); |
461 MenuItemMap::iterator i = context_items_.find(extension_id); | |
462 if (i == context_items_.end()) { | 462 if (i == context_items_.end()) { |
463 NOTREACHED(); | 463 NOTREACHED(); |
464 return false; | 464 return false; |
465 } | 465 } |
466 | 466 |
467 bool result = false; | 467 bool result = false; |
468 std::set<MenuItem::Id> items_removed; | 468 std::set<MenuItem::Id> items_removed; |
469 MenuItem::List& list = i->second; | 469 MenuItem::List& list = i->second; |
470 MenuItem::List::iterator j; | 470 MenuItem::List::iterator j; |
471 for (j = list.begin(); j < list.end(); ++j) { | 471 for (j = list.begin(); j < list.end(); ++j) { |
(...skipping 24 matching lines...) Expand all Loading... | |
496 | 496 |
497 // Clear entries from the items_by_id_ map. | 497 // Clear entries from the items_by_id_ map. |
498 std::set<MenuItem::Id>::iterator removed_iter; | 498 std::set<MenuItem::Id>::iterator removed_iter; |
499 for (removed_iter = items_removed.begin(); | 499 for (removed_iter = items_removed.begin(); |
500 removed_iter != items_removed.end(); | 500 removed_iter != items_removed.end(); |
501 ++removed_iter) { | 501 ++removed_iter) { |
502 items_by_id_.erase(*removed_iter); | 502 items_by_id_.erase(*removed_iter); |
503 } | 503 } |
504 | 504 |
505 if (list.empty()) { | 505 if (list.empty()) { |
506 context_items_.erase(extension_id); | 506 context_items_.erase(id.extension_key); |
507 icon_manager_.RemoveIcon(extension_id); | 507 icon_manager_.RemoveIcon(id.extension_key.extension_id); |
508 } | 508 } |
509 return result; | 509 return result; |
510 } | 510 } |
511 | 511 |
512 void MenuManager::RemoveAllContextItems(const std::string& extension_id) { | 512 void MenuManager::RemoveAllContextItems( |
513 const MenuItem::ExtensionKey& extension_key) { | |
513 MenuItem::List::iterator i; | 514 MenuItem::List::iterator i; |
514 for (i = context_items_[extension_id].begin(); | 515 for (i = context_items_[extension_key].begin(); |
515 i != context_items_[extension_id].end(); ++i) { | 516 i != context_items_[extension_key].end(); |
517 ++i) { | |
516 MenuItem* item = *i; | 518 MenuItem* item = *i; |
517 items_by_id_.erase(item->id()); | 519 items_by_id_.erase(item->id()); |
518 | 520 |
519 // Remove descendants from this item and erase them from the lookup cache. | 521 // Remove descendants from this item and erase them from the lookup cache. |
520 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants(); | 522 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants(); |
521 std::set<MenuItem::Id>::const_iterator j; | 523 std::set<MenuItem::Id>::const_iterator j; |
522 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) { | 524 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) { |
523 items_by_id_.erase(*j); | 525 items_by_id_.erase(*j); |
524 } | 526 } |
525 } | 527 } |
526 STLDeleteElements(&context_items_[extension_id]); | 528 STLDeleteElements(&context_items_[extension_key]); |
527 context_items_.erase(extension_id); | 529 context_items_.erase(extension_key); |
528 icon_manager_.RemoveIcon(extension_id); | 530 icon_manager_.RemoveIcon(extension_key.extension_id); |
529 } | 531 } |
530 | 532 |
531 MenuItem* MenuManager::GetItemById(const MenuItem::Id& id) const { | 533 MenuItem* MenuManager::GetItemById(const MenuItem::Id& id) const { |
532 std::map<MenuItem::Id, MenuItem*>::const_iterator i = | 534 std::map<MenuItem::Id, MenuItem*>::const_iterator i = |
533 items_by_id_.find(id); | 535 items_by_id_.find(id); |
534 if (i != items_by_id_.end()) | 536 if (i != items_by_id_.end()) |
535 return i->second; | 537 return i->second; |
536 else | 538 else |
537 return NULL; | 539 return NULL; |
538 } | 540 } |
539 | 541 |
540 void MenuManager::RadioItemSelected(MenuItem* item) { | 542 void MenuManager::RadioItemSelected(MenuItem* item) { |
541 // If this is a child item, we need to get a handle to the list from its | 543 // If this is a child item, we need to get a handle to the list from its |
542 // parent. Otherwise get a handle to the top-level list. | 544 // parent. Otherwise get a handle to the top-level list. |
543 const MenuItem::List* list = NULL; | 545 const MenuItem::List* list = NULL; |
544 if (item->parent_id()) { | 546 if (item->parent_id()) { |
545 MenuItem* parent = GetItemById(*item->parent_id()); | 547 MenuItem* parent = GetItemById(*item->parent_id()); |
546 if (!parent) { | 548 if (!parent) { |
547 NOTREACHED(); | 549 NOTREACHED(); |
548 return; | 550 return; |
549 } | 551 } |
550 list = &(parent->children()); | 552 list = &(parent->children()); |
551 } else { | 553 } else { |
552 if (context_items_.find(item->extension_id()) == context_items_.end()) { | 554 const MenuItem::ExtensionKey& key = item->id().extension_key; |
555 if (context_items_.find(key) == context_items_.end()) { | |
553 NOTREACHED(); | 556 NOTREACHED(); |
554 return; | 557 return; |
555 } | 558 } |
556 list = &context_items_[item->extension_id()]; | 559 list = &context_items_[key]; |
557 } | 560 } |
558 | 561 |
559 // Find where |item| is in the list. | 562 // Find where |item| is in the list. |
560 MenuItem::List::const_iterator item_location; | 563 MenuItem::List::const_iterator item_location; |
561 for (item_location = list->begin(); item_location != list->end(); | 564 for (item_location = list->begin(); item_location != list->end(); |
562 ++item_location) { | 565 ++item_location) { |
563 if (*item_location == item) | 566 if (*item_location == item) |
564 break; | 567 break; |
565 } | 568 } |
566 if (item_location == list->end()) { | 569 if (item_location == list->end()) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
603 if (!event_router) | 606 if (!event_router) |
604 return; | 607 return; |
605 | 608 |
606 MenuItem* item = GetItemById(menu_item_id); | 609 MenuItem* item = GetItemById(menu_item_id); |
607 if (!item) | 610 if (!item) |
608 return; | 611 return; |
609 | 612 |
610 // ExtensionService/Extension can be NULL in unit tests :( | 613 // ExtensionService/Extension can be NULL in unit tests :( |
611 ExtensionService* service = | 614 ExtensionService* service = |
612 ExtensionSystem::Get(profile_)->extension_service(); | 615 ExtensionSystem::Get(profile_)->extension_service(); |
613 const Extension* extension = service ? | 616 const Extension* extension = |
614 service->extensions()->GetByID(menu_item_id.extension_id) : NULL; | 617 service ? service->extensions()->GetByID(item->extension_id()) : NULL; |
615 | 618 |
616 if (item->type() == MenuItem::RADIO) | 619 if (item->type() == MenuItem::RADIO) |
617 RadioItemSelected(item); | 620 RadioItemSelected(item); |
618 | 621 |
619 scoped_ptr<base::ListValue> args(new base::ListValue()); | 622 scoped_ptr<base::ListValue> args(new base::ListValue()); |
620 | 623 |
621 base::DictionaryValue* properties = new base::DictionaryValue(); | 624 base::DictionaryValue* properties = new base::DictionaryValue(); |
622 SetIdKeyValue(properties, "menuItemId", item->id()); | 625 SetIdKeyValue(properties, "menuItemId", item->id()); |
623 if (item->parent_id()) | 626 if (item->parent_id()) |
624 SetIdKeyValue(properties, "parentMenuItemId", *item->parent_id()); | 627 SetIdKeyValue(properties, "parentMenuItemId", *item->parent_id()); |
(...skipping 14 matching lines...) Expand all Loading... | |
639 AddURLProperty(properties, "linkUrl", params.unfiltered_link_url); | 642 AddURLProperty(properties, "linkUrl", params.unfiltered_link_url); |
640 AddURLProperty(properties, "srcUrl", params.src_url); | 643 AddURLProperty(properties, "srcUrl", params.src_url); |
641 AddURLProperty(properties, "pageUrl", params.page_url); | 644 AddURLProperty(properties, "pageUrl", params.page_url); |
642 AddURLProperty(properties, "frameUrl", params.frame_url); | 645 AddURLProperty(properties, "frameUrl", params.frame_url); |
643 | 646 |
644 if (params.selection_text.length() > 0) | 647 if (params.selection_text.length() > 0) |
645 properties->SetString("selectionText", params.selection_text); | 648 properties->SetString("selectionText", params.selection_text); |
646 | 649 |
647 properties->SetBoolean("editable", params.is_editable); | 650 properties->SetBoolean("editable", params.is_editable); |
648 | 651 |
652 WebViewGuest* webview_guest = WebViewGuest::FromWebContents(web_contents); | |
653 if (webview_guest) { | |
654 // This is used in webview_custom_bindings.js. | |
655 // The property is not exposed to developer API. | |
656 properties->SetInteger("webviewInstanceId", | |
657 webview_guest->view_instance_id()); | |
658 } | |
659 | |
649 args->Append(properties); | 660 args->Append(properties); |
650 | 661 |
651 // Add the tab info to the argument list. | 662 // Add the tab info to the argument list. |
652 // No tab info in a platform app. | 663 // No tab info in a platform app. |
653 if (!extension || !extension->is_platform_app()) { | 664 if (!extension || !extension->is_platform_app()) { |
654 // Note: web_contents are NULL in unit tests :( | 665 // Note: web_contents are NULL in unit tests :( |
655 if (web_contents) { | 666 if (web_contents) { |
656 args->Append(ExtensionTabUtil::CreateTabValue(web_contents)); | 667 args->Append(ExtensionTabUtil::CreateTabValue(web_contents)); |
657 } else { | 668 } else { |
658 args->Append(new base::DictionaryValue()); | 669 args->Append(new base::DictionaryValue()); |
659 } | 670 } |
660 } | 671 } |
661 | 672 |
662 if (item->type() == MenuItem::CHECKBOX || | 673 if (item->type() == MenuItem::CHECKBOX || |
663 item->type() == MenuItem::RADIO) { | 674 item->type() == MenuItem::RADIO) { |
664 bool was_checked = item->checked(); | 675 bool was_checked = item->checked(); |
665 properties->SetBoolean("wasChecked", was_checked); | 676 properties->SetBoolean("wasChecked", was_checked); |
666 | 677 |
667 // RADIO items always get set to true when you click on them, but CHECKBOX | 678 // RADIO items always get set to true when you click on them, but CHECKBOX |
668 // items get their state toggled. | 679 // items get their state toggled. |
669 bool checked = | 680 bool checked = |
670 (item->type() == MenuItem::RADIO) ? true : !was_checked; | 681 (item->type() == MenuItem::RADIO) ? true : !was_checked; |
671 | 682 |
672 item->SetChecked(checked); | 683 item->SetChecked(checked); |
673 properties->SetBoolean("checked", item->checked()); | 684 properties->SetBoolean("checked", item->checked()); |
674 | 685 |
675 if (extension) | 686 if (extension) |
676 WriteToStorage(extension); | 687 WriteToStorage(extension, item->id().extension_key); |
677 } | 688 } |
678 | 689 |
679 // Note: web_contents are NULL in unit tests :( | 690 // Note: web_contents are NULL in unit tests :( |
680 if (web_contents && extensions::TabHelper::FromWebContents(web_contents)) { | 691 if (web_contents && extensions::TabHelper::FromWebContents(web_contents)) { |
681 extensions::TabHelper::FromWebContents(web_contents)-> | 692 extensions::TabHelper::FromWebContents(web_contents)-> |
682 active_tab_permission_granter()->GrantIfRequested(extension); | 693 active_tab_permission_granter()->GrantIfRequested(extension); |
683 } | 694 } |
684 | 695 |
685 { | 696 { |
697 // Dispatch to menu item's .onclick handler. | |
686 scoped_ptr<Event> event(new Event( | 698 scoped_ptr<Event> event(new Event( |
687 event_names::kOnContextMenus, | 699 event_names::kOnContextMenus, |
688 scoped_ptr<base::ListValue>(args->DeepCopy()))); | 700 scoped_ptr<base::ListValue>(args->DeepCopy()))); |
689 event->restrict_to_browser_context = profile; | 701 event->restrict_to_browser_context = profile; |
690 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; | 702 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; |
691 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); | 703 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); |
692 } | 704 } |
693 { | 705 { |
694 scoped_ptr<Event> event(new Event(context_menus::OnClicked::kEventName, | 706 // Dispatch to .contextMenus.onClicked handler. |
695 args.Pass())); | 707 scoped_ptr<Event> event( |
708 new Event(webview_guest ? event_names::kOnWebviewContextMenus | |
709 : context_menus::OnClicked::kEventName, | |
710 args.Pass())); | |
696 event->restrict_to_browser_context = profile; | 711 event->restrict_to_browser_context = profile; |
697 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; | 712 event->user_gesture = EventRouter::USER_GESTURE_ENABLED; |
713 if (webview_guest) | |
714 event->filter_info.SetInstanceID(webview_guest->view_instance_id()); | |
698 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); | 715 event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); |
699 } | 716 } |
700 } | 717 } |
701 | 718 |
702 void MenuManager::SanitizeRadioList(const MenuItem::List& item_list) { | 719 void MenuManager::SanitizeRadioList(const MenuItem::List& item_list) { |
703 MenuItem::List::const_iterator i = item_list.begin(); | 720 MenuItem::List::const_iterator i = item_list.begin(); |
704 while (i != item_list.end()) { | 721 while (i != item_list.end()) { |
705 if ((*i)->type() != MenuItem::RADIO) { | 722 if ((*i)->type() != MenuItem::RADIO) { |
706 ++i; | 723 ++i; |
707 break; | 724 break; |
(...skipping 28 matching lines...) Expand all Loading... | |
736 bool MenuManager::ItemUpdated(const MenuItem::Id& id) { | 753 bool MenuManager::ItemUpdated(const MenuItem::Id& id) { |
737 if (!ContainsKey(items_by_id_, id)) | 754 if (!ContainsKey(items_by_id_, id)) |
738 return false; | 755 return false; |
739 | 756 |
740 MenuItem* menu_item = GetItemById(id); | 757 MenuItem* menu_item = GetItemById(id); |
741 DCHECK(menu_item); | 758 DCHECK(menu_item); |
742 | 759 |
743 if (menu_item->parent_id()) { | 760 if (menu_item->parent_id()) { |
744 SanitizeRadioList(GetItemById(*menu_item->parent_id())->children()); | 761 SanitizeRadioList(GetItemById(*menu_item->parent_id())->children()); |
745 } else { | 762 } else { |
746 std::string extension_id = menu_item->extension_id(); | 763 MenuItemMap::iterator i = |
747 MenuItemMap::iterator i = context_items_.find(extension_id); | 764 context_items_.find(menu_item->id().extension_key); |
748 if (i == context_items_.end()) { | 765 if (i == context_items_.end()) { |
749 NOTREACHED(); | 766 NOTREACHED(); |
750 return false; | 767 return false; |
751 } | 768 } |
752 SanitizeRadioList(i->second); | 769 SanitizeRadioList(i->second); |
753 } | 770 } |
754 | 771 |
755 return true; | 772 return true; |
756 } | 773 } |
757 | 774 |
758 void MenuManager::WriteToStorage(const Extension* extension) { | 775 void MenuManager::WriteToStorage(const Extension* extension, |
776 const MenuItem::ExtensionKey& extension_key) { | |
759 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) | 777 if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
760 return; | 778 return; |
761 const MenuItem::List* top_items = MenuItems(extension->id()); | 779 // <webview> menu items are transient and not stored in storage. |
780 if (extension_key.webview_instance_id) | |
781 return; | |
782 const MenuItem::List* top_items = MenuItems(extension_key); | |
762 MenuItem::List all_items; | 783 MenuItem::List all_items; |
763 if (top_items) { | 784 if (top_items) { |
764 for (MenuItem::List::const_iterator i = top_items->begin(); | 785 for (MenuItem::List::const_iterator i = top_items->begin(); |
765 i != top_items->end(); ++i) { | 786 i != top_items->end(); ++i) { |
787 DCHECK(!(*i)->id().extension_key.webview_instance_id); | |
766 (*i)->GetFlattenedSubtree(&all_items); | 788 (*i)->GetFlattenedSubtree(&all_items); |
767 } | 789 } |
768 } | 790 } |
769 | 791 |
770 if (store_) | 792 if (store_) { |
771 store_->SetExtensionValue(extension->id(), kContextMenusKey, | 793 store_->SetExtensionValue(extension->id(), kContextMenusKey, |
772 MenuItemsToValue(all_items)); | 794 MenuItemsToValue(all_items)); |
795 } | |
773 } | 796 } |
774 | 797 |
775 void MenuManager::ReadFromStorage(const std::string& extension_id, | 798 void MenuManager::ReadFromStorage(const std::string& extension_id, |
776 scoped_ptr<base::Value> value) { | 799 scoped_ptr<base::Value> value) { |
777 const Extension* extension = | 800 const Extension* extension = |
778 ExtensionSystem::Get(profile_)->extension_service()->extensions()-> | 801 ExtensionSystem::Get(profile_)->extension_service()->extensions()-> |
779 GetByID(extension_id); | 802 GetByID(extension_id); |
780 if (!extension) | 803 if (!extension) |
781 return; | 804 return; |
782 | 805 |
(...skipping 14 matching lines...) Expand all Loading... | |
797 } | 820 } |
798 | 821 |
799 void MenuManager::Observe(int type, | 822 void MenuManager::Observe(int type, |
800 const content::NotificationSource& source, | 823 const content::NotificationSource& source, |
801 const content::NotificationDetails& details) { | 824 const content::NotificationDetails& details) { |
802 switch (type) { | 825 switch (type) { |
803 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | 826 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
804 // Remove menu items for disabled/uninstalled extensions. | 827 // Remove menu items for disabled/uninstalled extensions. |
805 const Extension* extension = | 828 const Extension* extension = |
806 content::Details<UnloadedExtensionInfo>(details)->extension; | 829 content::Details<UnloadedExtensionInfo>(details)->extension; |
807 if (ContainsKey(context_items_, extension->id())) { | 830 MenuItem::ExtensionKey extension_key(extension->id()); |
808 RemoveAllContextItems(extension->id()); | 831 if (ContainsKey(context_items_, extension_key)) { |
832 RemoveAllContextItems(extension_key); | |
809 } | 833 } |
810 break; | 834 break; |
811 } | 835 } |
812 case chrome::NOTIFICATION_EXTENSION_LOADED: { | 836 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
813 const Extension* extension = | 837 const Extension* extension = |
814 content::Details<const Extension>(details).ptr(); | 838 content::Details<const Extension>(details).ptr(); |
815 if (store_ && BackgroundInfo::HasLazyBackgroundPage(extension)) { | 839 if (store_ && BackgroundInfo::HasLazyBackgroundPage(extension)) { |
816 store_->GetExtensionValue(extension->id(), kContextMenusKey, | 840 store_->GetExtensionValue(extension->id(), kContextMenusKey, |
817 base::Bind(&MenuManager::ReadFromStorage, | 841 base::Bind(&MenuManager::ReadFromStorage, |
818 AsWeakPtr(), extension->id())); | 842 AsWeakPtr(), extension->id())); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
852 items_to_remove.insert(iter->first); | 876 items_to_remove.insert(iter->first); |
853 } | 877 } |
854 | 878 |
855 std::set<MenuItem::Id>::iterator remove_iter; | 879 std::set<MenuItem::Id>::iterator remove_iter; |
856 for (remove_iter = items_to_remove.begin(); | 880 for (remove_iter = items_to_remove.begin(); |
857 remove_iter != items_to_remove.end(); | 881 remove_iter != items_to_remove.end(); |
858 ++remove_iter) | 882 ++remove_iter) |
859 RemoveContextMenuItem(*remove_iter); | 883 RemoveContextMenuItem(*remove_iter); |
860 } | 884 } |
861 | 885 |
886 MenuItem::ExtensionKey::ExtensionKey() : webview_instance_id(0) {} | |
887 | |
888 MenuItem::ExtensionKey::ExtensionKey(const std::string& extension_id, | |
889 int webview_instance_id) | |
890 : extension_id(extension_id), webview_instance_id(webview_instance_id) {} | |
891 | |
892 MenuItem::ExtensionKey::ExtensionKey(const std::string& extension_id) | |
893 : extension_id(extension_id), webview_instance_id(0) {} | |
894 | |
895 bool MenuItem::ExtensionKey::operator==(const ExtensionKey& other) const { | |
896 return extension_id == other.extension_id && | |
897 webview_instance_id == other.webview_instance_id; | |
898 } | |
899 | |
900 bool MenuItem::ExtensionKey::operator<(const ExtensionKey& other) const { | |
901 if (webview_instance_id != other.webview_instance_id) | |
Yoyo Zhou
2014/03/07 02:40:30
nit: I would sort using extension id as the primar
lazyboy
2014/03/07 06:38:03
Done.
| |
902 return webview_instance_id < other.webview_instance_id; | |
903 | |
904 return extension_id < other.extension_id; | |
905 } | |
906 | |
907 bool MenuItem::ExtensionKey::operator!=(const ExtensionKey& other) const { | |
908 return !(*this == other); | |
909 } | |
910 | |
911 bool MenuItem::ExtensionKey::empty() const { | |
912 return extension_id.empty() && !webview_instance_id; | |
913 } | |
914 | |
862 MenuItem::Id::Id() : incognito(false), uid(0) {} | 915 MenuItem::Id::Id() : incognito(false), uid(0) {} |
863 | 916 |
864 MenuItem::Id::Id(bool incognito, const std::string& extension_id) | 917 MenuItem::Id::Id(bool incognito, const MenuItem::ExtensionKey& extension_key) |
865 : incognito(incognito), extension_id(extension_id), uid(0) {} | 918 : incognito(incognito), extension_key(extension_key), uid(0) {} |
866 | 919 |
867 MenuItem::Id::~Id() { | 920 MenuItem::Id::~Id() { |
868 } | 921 } |
869 | 922 |
870 bool MenuItem::Id::operator==(const Id& other) const { | 923 bool MenuItem::Id::operator==(const Id& other) const { |
871 return (incognito == other.incognito && | 924 return (incognito == other.incognito && |
872 extension_id == other.extension_id && | 925 extension_key == other.extension_key && uid == other.uid && |
873 uid == other.uid && | |
874 string_uid == other.string_uid); | 926 string_uid == other.string_uid); |
875 } | 927 } |
876 | 928 |
877 bool MenuItem::Id::operator!=(const Id& other) const { | 929 bool MenuItem::Id::operator!=(const Id& other) const { |
878 return !(*this == other); | 930 return !(*this == other); |
879 } | 931 } |
880 | 932 |
881 bool MenuItem::Id::operator<(const Id& other) const { | 933 bool MenuItem::Id::operator<(const Id& other) const { |
882 if (incognito < other.incognito) | 934 if (incognito < other.incognito) |
883 return true; | 935 return true; |
884 if (incognito == other.incognito) { | 936 if (incognito == other.incognito) { |
885 if (extension_id < other.extension_id) | 937 if (extension_key < other.extension_key) |
886 return true; | 938 return true; |
887 if (extension_id == other.extension_id) { | 939 if (extension_key == other.extension_key) { |
888 if (uid < other.uid) | 940 if (uid < other.uid) |
889 return true; | 941 return true; |
890 if (uid == other.uid) | 942 if (uid == other.uid) |
891 return string_uid < other.string_uid; | 943 return string_uid < other.string_uid; |
892 } | 944 } |
893 } | 945 } |
894 return false; | 946 return false; |
895 } | 947 } |
896 | 948 |
897 } // namespace extensions | 949 } // namespace extensions |
OLD | NEW |