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/ui/views/wrench_menu.h" | 5 #include "chrome/browser/ui/views/wrench_menu.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/string_number_conversions.h" | 9 #include "base/string_number_conversions.h" |
10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
11 #include "chrome/app/chrome_command_ids.h" | 11 #include "chrome/app/chrome_command_ids.h" |
| 12 #include "chrome/browser/bookmarks/bookmark_model.h" |
12 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
13 #include "chrome/browser/ui/browser.h" | 14 #include "chrome/browser/ui/browser.h" |
| 15 #include "chrome/browser/ui/browser_window.h" |
| 16 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h" |
14 #include "content/browser/tab_contents/tab_contents.h" | 17 #include "content/browser/tab_contents/tab_contents.h" |
15 #include "content/browser/user_metrics.h" | 18 #include "content/browser/user_metrics.h" |
16 #include "content/common/notification_observer.h" | 19 #include "content/common/notification_observer.h" |
17 #include "content/common/notification_registrar.h" | 20 #include "content/common/notification_registrar.h" |
18 #include "content/common/notification_source.h" | 21 #include "content/common/notification_source.h" |
19 #include "content/common/notification_type.h" | 22 #include "content/common/notification_type.h" |
20 #include "grit/chromium_strings.h" | 23 #include "grit/chromium_strings.h" |
21 #include "grit/generated_resources.h" | 24 #include "grit/generated_resources.h" |
22 #include "grit/theme_resources.h" | 25 #include "grit/theme_resources.h" |
23 #include "third_party/skia/include/core/SkPaint.h" | 26 #include "third_party/skia/include/core/SkPaint.h" |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 int zoom_label_width_; | 560 int zoom_label_width_; |
558 | 561 |
559 DISALLOW_COPY_AND_ASSIGN(ZoomView); | 562 DISALLOW_COPY_AND_ASSIGN(ZoomView); |
560 }; | 563 }; |
561 | 564 |
562 // WrenchMenu ------------------------------------------------------------------ | 565 // WrenchMenu ------------------------------------------------------------------ |
563 | 566 |
564 WrenchMenu::WrenchMenu(Browser* browser) | 567 WrenchMenu::WrenchMenu(Browser* browser) |
565 : browser_(browser), | 568 : browser_(browser), |
566 selected_menu_model_(NULL), | 569 selected_menu_model_(NULL), |
567 selected_index_(0) { | 570 selected_index_(0), |
| 571 bookmark_menu_(NULL), |
| 572 first_bookmark_command_id_(0) { |
568 } | 573 } |
569 | 574 |
570 void WrenchMenu::Init(ui::MenuModel* model) { | 575 void WrenchMenu::Init(ui::MenuModel* model) { |
571 DCHECK(!root_.get()); | 576 DCHECK(!root_.get()); |
572 root_.reset(new MenuItemView(this)); | 577 root_.reset(new MenuItemView(this)); |
573 root_->set_has_icons(true); // We have checks, radios and icons, set this | 578 root_->set_has_icons(true); // We have checks, radios and icons, set this |
574 // so we get the taller menu style. | 579 // so we get the taller menu style. |
575 int next_id = 1; | 580 int next_id = 1; |
576 PopulateMenu(root_.get(), model, &next_id); | 581 PopulateMenu(root_.get(), model, &next_id); |
| 582 first_bookmark_command_id_ = next_id + 1; |
577 } | 583 } |
578 | 584 |
579 void WrenchMenu::RunMenu(views::MenuButton* host) { | 585 void WrenchMenu::RunMenu(views::MenuButton* host) { |
580 // Up the ref count while the menu is displaying. This way if the window is | 586 // Up the ref count while the menu is displaying. This way if the window is |
581 // deleted while we're running we won't prematurely delete the menu. | 587 // deleted while we're running we won't prematurely delete the menu. |
582 // TODO(sky): fix this, the menu should really take ownership of the menu | 588 // TODO(sky): fix this, the menu should really take ownership of the menu |
583 // (57890). | 589 // (57890). |
584 scoped_refptr<WrenchMenu> dont_delete_while_running(this); | 590 scoped_refptr<WrenchMenu> dont_delete_while_running(this); |
585 gfx::Point screen_loc; | 591 gfx::Point screen_loc; |
586 views::View::ConvertPointToScreen(host, &screen_loc); | 592 views::View::ConvertPointToScreen(host, &screen_loc); |
587 gfx::Rect bounds(screen_loc, host->size()); | 593 gfx::Rect bounds(screen_loc, host->size()); |
588 UserMetrics::RecordAction(UserMetricsAction("ShowAppMenu")); | 594 UserMetrics::RecordAction(UserMetricsAction("ShowAppMenu")); |
589 root_->RunMenuAt(host->GetWindow()->GetNativeWindow(), host, bounds, | 595 root_->RunMenuAt(host->GetWindow()->GetNativeWindow(), host, bounds, |
590 base::i18n::IsRTL() ? MenuItemView::TOPLEFT : MenuItemView::TOPRIGHT, | 596 base::i18n::IsRTL() ? MenuItemView::TOPLEFT : MenuItemView::TOPRIGHT, |
591 true); | 597 true); |
| 598 if (bookmark_menu_delegate_.get()) { |
| 599 BookmarkModel* model = browser_->profile()->GetBookmarkModel(); |
| 600 if (model) |
| 601 model->RemoveObserver(this); |
| 602 } |
592 if (selected_menu_model_) | 603 if (selected_menu_model_) |
593 selected_menu_model_->ActivatedAt(selected_index_); | 604 selected_menu_model_->ActivatedAt(selected_index_); |
594 } | 605 } |
595 | 606 |
| 607 std::wstring WrenchMenu::GetTooltipText(int id, |
| 608 const gfx::Point& p) { |
| 609 return is_bookmark_command(id) ? |
| 610 bookmark_menu_delegate_->GetTooltipText(id, p) : std::wstring(); |
| 611 } |
| 612 |
| 613 bool WrenchMenu::IsTriggerableEvent(views::MenuItemView* menu, |
| 614 const views::MouseEvent& e) { |
| 615 return is_bookmark_command(menu->GetCommand()) ? |
| 616 bookmark_menu_delegate_->IsTriggerableEvent(menu, e) : |
| 617 MenuDelegate::IsTriggerableEvent(menu, e); |
| 618 } |
| 619 |
| 620 bool WrenchMenu::GetDropFormats( |
| 621 MenuItemView* menu, |
| 622 int* formats, |
| 623 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) { |
| 624 CreateBookmarkMenu(); |
| 625 return bookmark_menu_delegate_.get() && |
| 626 bookmark_menu_delegate_->GetDropFormats(menu, formats, custom_formats); |
| 627 } |
| 628 |
| 629 bool WrenchMenu::AreDropTypesRequired(MenuItemView* menu) { |
| 630 CreateBookmarkMenu(); |
| 631 return bookmark_menu_delegate_.get() && |
| 632 bookmark_menu_delegate_->AreDropTypesRequired(menu); |
| 633 } |
| 634 |
| 635 bool WrenchMenu::CanDrop(MenuItemView* menu, |
| 636 const ui::OSExchangeData& data) { |
| 637 CreateBookmarkMenu(); |
| 638 return bookmark_menu_delegate_.get() && |
| 639 bookmark_menu_delegate_->CanDrop(menu, data); |
| 640 } |
| 641 |
| 642 int WrenchMenu::GetDropOperation( |
| 643 MenuItemView* item, |
| 644 const views::DropTargetEvent& event, |
| 645 DropPosition* position) { |
| 646 return is_bookmark_command(item->GetCommand()) ? |
| 647 bookmark_menu_delegate_->GetDropOperation(item, event, position) : |
| 648 ui::DragDropTypes::DRAG_NONE; |
| 649 } |
| 650 |
| 651 int WrenchMenu::OnPerformDrop(MenuItemView* menu, |
| 652 DropPosition position, |
| 653 const views::DropTargetEvent& event) { |
| 654 if (!is_bookmark_command(menu->GetCommand())) |
| 655 return ui::DragDropTypes::DRAG_NONE; |
| 656 |
| 657 int result = bookmark_menu_delegate_->OnPerformDrop(menu, position, event); |
| 658 return result; |
| 659 } |
| 660 |
| 661 bool WrenchMenu::ShowContextMenu(MenuItemView* source, |
| 662 int id, |
| 663 const gfx::Point& p, |
| 664 bool is_mouse_gesture) { |
| 665 return is_bookmark_command(id) ? |
| 666 bookmark_menu_delegate_->ShowContextMenu(source, id, p, |
| 667 is_mouse_gesture) : |
| 668 false; |
| 669 } |
| 670 |
| 671 bool WrenchMenu::CanDrag(MenuItemView* menu) { |
| 672 return is_bookmark_command(menu->GetCommand()) ? |
| 673 bookmark_menu_delegate_->CanDrag(menu) : false; |
| 674 } |
| 675 |
| 676 void WrenchMenu::WriteDragData(MenuItemView* sender, |
| 677 ui::OSExchangeData* data) { |
| 678 DCHECK(is_bookmark_command(sender->GetCommand())); |
| 679 return bookmark_menu_delegate_->WriteDragData(sender, data); |
| 680 } |
| 681 |
| 682 int WrenchMenu::GetDragOperations(MenuItemView* sender) { |
| 683 return is_bookmark_command(sender->GetCommand()) ? |
| 684 bookmark_menu_delegate_->GetDragOperations(sender) : |
| 685 MenuDelegate::GetDragOperations(sender); |
| 686 } |
| 687 |
| 688 int WrenchMenu::GetMaxWidthForMenu(MenuItemView* menu) { |
| 689 return is_bookmark_command(menu->GetCommand()) ? |
| 690 bookmark_menu_delegate_->GetMaxWidthForMenu(menu) : |
| 691 MenuDelegate::GetMaxWidthForMenu(menu); |
| 692 } |
| 693 |
596 bool WrenchMenu::IsItemChecked(int id) const { | 694 bool WrenchMenu::IsItemChecked(int id) const { |
| 695 if (!is_bookmark_command(id)) |
| 696 return false; |
| 697 |
597 const Entry& entry = id_to_entry_.find(id)->second; | 698 const Entry& entry = id_to_entry_.find(id)->second; |
598 return entry.first->IsItemCheckedAt(entry.second); | 699 return entry.first->IsItemCheckedAt(entry.second); |
599 } | 700 } |
600 | 701 |
601 bool WrenchMenu::IsCommandEnabled(int id) const { | 702 bool WrenchMenu::IsCommandEnabled(int id) const { |
| 703 if (is_bookmark_command(id)) |
| 704 return true; |
| 705 |
602 if (id == 0) | 706 if (id == 0) |
603 return false; // The root item. | 707 return false; // The root item. |
604 | 708 |
605 const Entry& entry = id_to_entry_.find(id)->second; | 709 const Entry& entry = id_to_entry_.find(id)->second; |
606 int command_id = entry.first->GetCommandIdAt(entry.second); | 710 int command_id = entry.first->GetCommandIdAt(entry.second); |
607 // The items representing the cut (cut/copy/paste) and zoom menu | 711 // The items representing the cut (cut/copy/paste) and zoom menu |
608 // (increment/decrement/reset) are always enabled. The child views of these | 712 // (increment/decrement/reset) are always enabled. The child views of these |
609 // items enabled state updates appropriately. | 713 // items enabled state updates appropriately. |
610 return command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS || | 714 return command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS || |
611 entry.first->IsEnabledAt(entry.second); | 715 entry.first->IsEnabledAt(entry.second); |
612 } | 716 } |
613 | 717 |
614 void WrenchMenu::ExecuteCommand(int id) { | 718 void WrenchMenu::ExecuteCommand(int id, int mouse_event_flags) { |
| 719 if (is_bookmark_command(id)) { |
| 720 bookmark_menu_delegate_->ExecuteCommand(id, mouse_event_flags); |
| 721 return; |
| 722 } |
| 723 |
| 724 // Not a bookmark |
615 const Entry& entry = id_to_entry_.find(id)->second; | 725 const Entry& entry = id_to_entry_.find(id)->second; |
616 int command_id = entry.first->GetCommandIdAt(entry.second); | 726 int command_id = entry.first->GetCommandIdAt(entry.second); |
617 | 727 |
618 if (command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS) { | 728 if (command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS) { |
619 // These items are represented by child views. If ExecuteCommand is invoked | 729 // These items are represented by child views. If ExecuteCommand is invoked |
620 // it means the user clicked on the area around the buttons and we should | 730 // it means the user clicked on the area around the buttons and we should |
621 // not do anyting. | 731 // not do anyting. |
622 return; | 732 return; |
623 } | 733 } |
624 | 734 |
625 return entry.first->ActivatedAt(entry.second); | 735 return entry.first->ActivatedAt(entry.second); |
626 } | 736 } |
627 | 737 |
628 bool WrenchMenu::GetAccelerator(int id, views::Accelerator* accelerator) { | 738 bool WrenchMenu::GetAccelerator(int id, views::Accelerator* accelerator) { |
| 739 if (is_bookmark_command(id)) |
| 740 return false; |
| 741 |
629 const Entry& entry = id_to_entry_.find(id)->second; | 742 const Entry& entry = id_to_entry_.find(id)->second; |
630 int command_id = entry.first->GetCommandIdAt(entry.second); | 743 int command_id = entry.first->GetCommandIdAt(entry.second); |
631 if (command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS) { | 744 if (command_id == IDC_CUT || command_id == IDC_ZOOM_MINUS) { |
632 // These have special child views; don't show the accelerator for them. | 745 // These have special child views; don't show the accelerator for them. |
633 return false; | 746 return false; |
634 } | 747 } |
635 | 748 |
636 ui::Accelerator menu_accelerator; | 749 ui::Accelerator menu_accelerator; |
637 if (!entry.first->GetAcceleratorAt(entry.second, &menu_accelerator)) | 750 if (!entry.first->GetAcceleratorAt(entry.second, &menu_accelerator)) |
638 return false; | 751 return false; |
639 | 752 |
640 *accelerator = views::Accelerator(menu_accelerator.key_code(), | 753 *accelerator = views::Accelerator(menu_accelerator.key_code(), |
641 menu_accelerator.modifiers()); | 754 menu_accelerator.modifiers()); |
642 return true; | 755 return true; |
643 } | 756 } |
644 | 757 |
| 758 void WrenchMenu::WillShowMenu(MenuItemView* menu) { |
| 759 if (menu == bookmark_menu_) |
| 760 CreateBookmarkMenu(); |
| 761 } |
| 762 |
| 763 void WrenchMenu::BookmarkModelChanged() { |
| 764 root_->Cancel(); |
| 765 } |
| 766 |
645 WrenchMenu::~WrenchMenu() { | 767 WrenchMenu::~WrenchMenu() { |
646 } | 768 } |
647 | 769 |
648 void WrenchMenu::PopulateMenu(MenuItemView* parent, | 770 void WrenchMenu::PopulateMenu(MenuItemView* parent, |
649 MenuModel* model, | 771 MenuModel* model, |
650 int* next_id) { | 772 int* next_id) { |
651 int index_offset = model->GetFirstItemIndex(NULL); | 773 int index_offset = model->GetFirstItemIndex(NULL); |
652 for (int i = 0, max = model->GetItemCount(); i < max; ++i) { | 774 for (int i = 0, max = model->GetItemCount(); i < max; ++i) { |
653 int index = i + index_offset; | 775 int index = i + index_offset; |
654 | 776 |
655 MenuItemView* item = | 777 MenuItemView* item = |
656 AppendMenuItem(parent, model, index, model->GetTypeAt(index), next_id); | 778 AppendMenuItem(parent, model, index, model->GetTypeAt(index), next_id); |
657 | 779 |
658 if (model->GetTypeAt(index) == MenuModel::TYPE_SUBMENU) | 780 if (model->GetTypeAt(index) == MenuModel::TYPE_SUBMENU) |
659 PopulateMenu(item, model->GetSubmenuModelAt(index), next_id); | 781 PopulateMenu(item, model->GetSubmenuModelAt(index), next_id); |
660 | 782 |
661 if (model->GetCommandIdAt(index) == IDC_CUT) { | 783 switch (model->GetCommandIdAt(index)) { |
662 DCHECK_EQ(MenuModel::TYPE_COMMAND, model->GetTypeAt(index)); | 784 case IDC_CUT: |
663 DCHECK_LT(i + 2, max); | 785 DCHECK_EQ(MenuModel::TYPE_COMMAND, model->GetTypeAt(index)); |
664 DCHECK_EQ(IDC_COPY, model->GetCommandIdAt(index + 1)); | 786 DCHECK_LT(i + 2, max); |
665 DCHECK_EQ(IDC_PASTE, model->GetCommandIdAt(index + 2)); | 787 DCHECK_EQ(IDC_COPY, model->GetCommandIdAt(index + 1)); |
666 item->SetTitle(UTF16ToWide(l10n_util::GetStringUTF16(IDS_EDIT2))); | 788 DCHECK_EQ(IDC_PASTE, model->GetCommandIdAt(index + 2)); |
667 item->AddChildView( | 789 item->SetTitle(UTF16ToWide(l10n_util::GetStringUTF16(IDS_EDIT2))); |
668 new CutCopyPasteView(this, model, index, index + 1, index + 2)); | 790 item->AddChildView( |
669 i += 2; | 791 new CutCopyPasteView(this, model, index, index + 1, index + 2)); |
670 } else if (model->GetCommandIdAt(index) == IDC_ZOOM_MINUS) { | 792 i += 2; |
671 DCHECK_EQ(MenuModel::TYPE_COMMAND, model->GetTypeAt(index)); | 793 break; |
672 DCHECK_EQ(IDC_ZOOM_PLUS, model->GetCommandIdAt(index + 1)); | 794 |
673 DCHECK_EQ(IDC_FULLSCREEN, model->GetCommandIdAt(index + 2)); | 795 case IDC_ZOOM_MINUS: |
674 item->SetTitle(UTF16ToWide(l10n_util::GetStringUTF16(IDS_ZOOM_MENU2))); | 796 DCHECK_EQ(MenuModel::TYPE_COMMAND, model->GetTypeAt(index)); |
675 item->AddChildView( | 797 DCHECK_EQ(IDC_ZOOM_PLUS, model->GetCommandIdAt(index + 1)); |
676 new ZoomView(this, model, index, index + 1, index + 2)); | 798 DCHECK_EQ(IDC_FULLSCREEN, model->GetCommandIdAt(index + 2)); |
677 i += 2; | 799 item->SetTitle(UTF16ToWide(l10n_util::GetStringUTF16(IDS_ZOOM_MENU2))); |
| 800 item->AddChildView( |
| 801 new ZoomView(this, model, index, index + 1, index + 2)); |
| 802 i += 2; |
| 803 break; |
| 804 |
| 805 case IDC_BOOKMARKS_MENU: |
| 806 DCHECK(!bookmark_menu_); |
| 807 bookmark_menu_ = item; |
| 808 break; |
| 809 |
| 810 default: |
| 811 break; |
678 } | 812 } |
679 } | 813 } |
680 } | 814 } |
681 | 815 |
682 MenuItemView* WrenchMenu::AppendMenuItem(MenuItemView* parent, | 816 MenuItemView* WrenchMenu::AppendMenuItem(MenuItemView* parent, |
683 MenuModel* model, | 817 MenuModel* model, |
684 int index, | 818 int index, |
685 MenuModel::ItemType menu_type, | 819 MenuModel::ItemType menu_type, |
686 int* next_id) { | 820 int* next_id) { |
687 int id = (*next_id)++; | 821 int id = (*next_id)++; |
(...skipping 13 matching lines...) Expand all Loading... |
701 } | 835 } |
702 | 836 |
703 return menu_item; | 837 return menu_item; |
704 } | 838 } |
705 | 839 |
706 void WrenchMenu::CancelAndEvaluate(MenuModel* model, int index) { | 840 void WrenchMenu::CancelAndEvaluate(MenuModel* model, int index) { |
707 selected_menu_model_ = model; | 841 selected_menu_model_ = model; |
708 selected_index_ = index; | 842 selected_index_ = index; |
709 root_->Cancel(); | 843 root_->Cancel(); |
710 } | 844 } |
| 845 |
| 846 void WrenchMenu::CreateBookmarkMenu() { |
| 847 if (bookmark_menu_delegate_.get()) |
| 848 return; // Already created the menu. |
| 849 |
| 850 BookmarkModel* model = browser_->profile()->GetBookmarkModel(); |
| 851 if (!model->IsLoaded()) |
| 852 return; |
| 853 |
| 854 model->AddObserver(this); |
| 855 bookmark_menu_delegate_.reset( |
| 856 new BookmarkMenuDelegate(browser_->profile(), |
| 857 NULL, |
| 858 browser_->window()->GetNativeHandle(), |
| 859 first_bookmark_command_id_)); |
| 860 bookmark_menu_delegate_->Init( |
| 861 this, bookmark_menu_, model->GetBookmarkBarNode(), 0, |
| 862 BookmarkMenuDelegate::SHOW_OTHER_FOLDER); |
| 863 } |
OLD | NEW |