OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/views/extensions/browser_action_overflow_menu_controlle
r.h" | 5 #include "chrome/browser/views/extensions/browser_action_overflow_menu_controlle
r.h" |
6 | 6 |
7 #include "base/utf_string_conversions.h" | 7 #include "base/utf_string_conversions.h" |
8 #include "chrome/browser/browser_list.h" | 8 #include "chrome/browser/browser_list.h" |
9 #include "chrome/browser/tab_contents/tab_contents.h" | 9 #include "chrome/browser/tab_contents/tab_contents.h" |
10 #include "chrome/browser/views/browser_actions_container.h" | 10 #include "chrome/browser/views/browser_actions_container.h" |
| 11 #include "chrome/browser/views/extensions/browser_action_drag_data.h" |
11 #include "chrome/common/extensions/extension.h" | 12 #include "chrome/common/extensions/extension.h" |
12 #include "views/controls/menu/menu_item_view.h" | 13 #include "views/controls/menu/menu_item_view.h" |
13 | 14 |
14 BrowserActionOverflowMenuController::BrowserActionOverflowMenuController( | 15 BrowserActionOverflowMenuController::BrowserActionOverflowMenuController( |
15 BrowserActionsContainer* owner, | 16 BrowserActionsContainer* owner, |
16 views::MenuButton* menu_button, | 17 views::MenuButton* menu_button, |
17 const std::vector<BrowserActionView*>& views, | 18 const std::vector<BrowserActionView*>& views, |
18 int start_index) | 19 int start_index) |
19 : owner_(owner), | 20 : owner_(owner), |
| 21 observer_(NULL), |
20 menu_button_(menu_button), | 22 menu_button_(menu_button), |
21 views_(&views), | 23 views_(&views), |
22 start_index_(start_index) { | 24 start_index_(start_index), |
| 25 for_drop_(false) { |
23 menu_.reset(new views::MenuItemView(this)); | 26 menu_.reset(new views::MenuItemView(this)); |
24 menu_->set_has_icons(true); | 27 menu_->set_has_icons(true); |
25 | 28 |
26 TabContents* tab = BrowserList::GetLastActive()->GetSelectedTabContents(); | 29 TabContents* tab = BrowserList::GetLastActive()->GetSelectedTabContents(); |
27 int tab_id = tab->controller().session_id().id(); | 30 int tab_id = tab->controller().session_id().id(); |
28 | 31 |
29 size_t command_id = 0; | 32 size_t command_id = 0; |
30 for (size_t i = start_index; i < views_->size(); ++i) { | 33 for (size_t i = start_index; i < views_->size(); ++i) { |
31 BrowserActionView* view = (*views_)[i]; | 34 BrowserActionView* view = (*views_)[i]; |
32 SkBitmap icon = | 35 SkBitmap icon = |
33 view->button()->extension()->browser_action()->GetIcon(tab_id); | 36 view->button()->extension()->browser_action()->GetIcon(tab_id); |
34 if (icon.isNull()) | 37 if (icon.isNull()) |
35 icon = view->button()->default_icon(); | 38 icon = view->button()->default_icon(); |
36 menu_->AppendMenuItemWithIcon( | 39 menu_->AppendMenuItemWithIcon( |
37 command_id, | 40 command_id, |
38 UTF8ToWide(view->button()->extension()->name()), | 41 UTF8ToWide(view->button()->extension()->name()), |
39 icon); | 42 icon); |
40 ++command_id; | 43 ++command_id; |
41 } | 44 } |
42 } | 45 } |
43 | 46 |
44 BrowserActionOverflowMenuController::~BrowserActionOverflowMenuController() { | 47 BrowserActionOverflowMenuController::~BrowserActionOverflowMenuController() { |
| 48 if (observer_) |
| 49 observer_->NotifyMenuDeleted(this); |
45 } | 50 } |
46 | 51 |
47 bool BrowserActionOverflowMenuController::RunMenu(gfx::NativeWindow window) { | 52 bool BrowserActionOverflowMenuController::RunMenu(gfx::NativeWindow window, |
| 53 bool for_drop) { |
| 54 for_drop_ = for_drop; |
| 55 |
48 gfx::Rect bounds = menu_button_->GetBounds( | 56 gfx::Rect bounds = menu_button_->GetBounds( |
49 views::View::IGNORE_MIRRORING_TRANSFORMATION); | 57 views::View::IGNORE_MIRRORING_TRANSFORMATION); |
50 gfx::Point screen_loc; | 58 gfx::Point screen_loc; |
51 views::View::ConvertPointToScreen(menu_button_, &screen_loc); | 59 views::View::ConvertPointToScreen(menu_button_, &screen_loc); |
52 bounds.set_x(screen_loc.x()); | 60 bounds.set_x(screen_loc.x()); |
53 bounds.set_y(screen_loc.y()); | 61 bounds.set_y(screen_loc.y()); |
54 | 62 |
55 views::MenuItemView::AnchorPosition anchor = | 63 views::MenuItemView::AnchorPosition anchor = |
56 menu_button_->UILayoutIsRightToLeft() ? views::MenuItemView::TOPRIGHT : | 64 menu_button_->UILayoutIsRightToLeft() ? views::MenuItemView::TOPRIGHT : |
57 views::MenuItemView::TOPLEFT; | 65 views::MenuItemView::TOPLEFT; |
58 menu_->RunMenuAt(window, menu_button_, bounds, anchor, false); | 66 if (for_drop) { |
| 67 menu_->RunMenuForDropAt(window, bounds, anchor); |
| 68 } else { |
| 69 menu_->RunMenuAt(window, menu_button_, bounds, anchor, false); |
| 70 delete this; |
| 71 } |
59 return true; | 72 return true; |
60 } | 73 } |
61 | 74 |
62 void BrowserActionOverflowMenuController::CancelMenu() { | 75 void BrowserActionOverflowMenuController::CancelMenu() { |
63 if (context_menu_.get()) | 76 if (context_menu_.get()) |
64 context_menu_->Cancel(); | 77 context_menu_->Cancel(); |
65 menu_->Cancel(); | 78 menu_->Cancel(); |
66 } | 79 } |
67 | 80 |
68 void BrowserActionOverflowMenuController::ExecuteCommand(int id) { | 81 void BrowserActionOverflowMenuController::ExecuteCommand(int id) { |
69 BrowserActionView* view = (*views_)[start_index_ + id]; | 82 BrowserActionView* view = (*views_)[start_index_ + id]; |
70 owner_->OnBrowserActionExecuted(view->button()); | 83 owner_->OnBrowserActionExecuted(view->button()); |
71 } | 84 } |
72 | 85 |
73 bool BrowserActionOverflowMenuController::ShowContextMenu( | 86 bool BrowserActionOverflowMenuController::ShowContextMenu( |
74 views::MenuItemView* source, int id, int x, int y, bool is_mouse_gesture) { | 87 views::MenuItemView* source, int id, int x, int y, bool is_mouse_gesture) { |
75 if (!context_menu_.get()) | 88 if (!context_menu_.get()) |
76 context_menu_.reset(new ExtensionActionContextMenu()); | 89 context_menu_.reset(new ExtensionActionContextMenu()); |
77 // This blocks until the user choses something or dismisses. | 90 // This blocks until the user choses something or dismisses. |
78 context_menu_->Run((*views_)[start_index_ + id]->button()->extension(), | 91 context_menu_->Run((*views_)[start_index_ + id]->button()->extension(), |
79 gfx::Point(x, y)); | 92 gfx::Point(x, y)); |
80 | 93 |
81 // The user is done with the context menu, so we can close the underlying | 94 // The user is done with the context menu, so we can close the underlying |
82 // menu. | 95 // menu. |
83 menu_->Cancel(); | 96 menu_->Cancel(); |
84 | 97 |
85 return true; | 98 return true; |
86 } | 99 } |
| 100 |
| 101 void BrowserActionOverflowMenuController::DropMenuClosed( |
| 102 views::MenuItemView* menu) { |
| 103 delete this; |
| 104 } |
| 105 |
| 106 bool BrowserActionOverflowMenuController::GetDropFormats( |
| 107 views::MenuItemView* menu, |
| 108 int* formats, |
| 109 std::set<OSExchangeData::CustomFormat>* custom_formats) { |
| 110 custom_formats->insert(BrowserActionDragData::GetBrowserActionCustomFormat()); |
| 111 return true; |
| 112 } |
| 113 |
| 114 bool BrowserActionOverflowMenuController::AreDropTypesRequired( |
| 115 views::MenuItemView* menu) { |
| 116 return true; |
| 117 } |
| 118 |
| 119 bool BrowserActionOverflowMenuController::CanDrop( |
| 120 views::MenuItemView* menu, const OSExchangeData& data) { |
| 121 BrowserActionDragData drop_data; |
| 122 if (!drop_data.Read(data)) |
| 123 return false; |
| 124 return drop_data.IsFromProfile(owner_->profile()); |
| 125 } |
| 126 |
| 127 int BrowserActionOverflowMenuController::GetDropOperation( |
| 128 views::MenuItemView* item, |
| 129 const views::DropTargetEvent& event, |
| 130 DropPosition* position) { |
| 131 // Don't allow dropping from the BrowserActionContainer into slot 0 of the |
| 132 // overflow menu since once the move has taken place the item you are dragging |
| 133 // falls right out of the menu again once the user releases the button |
| 134 // (because we don't shrink the BrowserActionContainer when you do this). |
| 135 if ((item->GetCommand() == 0) && (*position == DROP_BEFORE)) { |
| 136 BrowserActionDragData drop_data; |
| 137 if (!drop_data.Read(event.GetData())) |
| 138 return DragDropTypes::DRAG_NONE; |
| 139 |
| 140 if (drop_data.index() < owner_->VisibleBrowserActions()) |
| 141 return DragDropTypes::DRAG_NONE; |
| 142 } |
| 143 |
| 144 return DragDropTypes::DRAG_MOVE; |
| 145 } |
| 146 |
| 147 int BrowserActionOverflowMenuController::OnPerformDrop( |
| 148 views::MenuItemView* menu, |
| 149 DropPosition position, |
| 150 const views::DropTargetEvent& event) { |
| 151 BrowserActionDragData drop_data; |
| 152 if (!drop_data.Read(event.GetData())) |
| 153 return DragDropTypes::DRAG_NONE; |
| 154 |
| 155 size_t drop_index; |
| 156 ViewForId(menu->GetCommand(), &drop_index); |
| 157 |
| 158 // When not dragging within the overflow menu (dragging an icon into the menu) |
| 159 // subtract one to get the right index. |
| 160 if (position == DROP_BEFORE && |
| 161 drop_data.index() < owner_->VisibleBrowserActions()) |
| 162 --drop_index; |
| 163 |
| 164 owner_->MoveBrowserAction(drop_data.id(), drop_index); |
| 165 |
| 166 if (for_drop_) |
| 167 delete this; |
| 168 return DragDropTypes::DRAG_MOVE; |
| 169 } |
| 170 |
| 171 bool BrowserActionOverflowMenuController::CanDrag(views::MenuItemView* menu) { |
| 172 return true; |
| 173 } |
| 174 |
| 175 void BrowserActionOverflowMenuController::WriteDragData( |
| 176 views::MenuItemView* sender, OSExchangeData* data) { |
| 177 size_t drag_index; |
| 178 BrowserActionView* view = ViewForId(sender->GetCommand(), &drag_index); |
| 179 std::string id = view->button()->extension()->id(); |
| 180 |
| 181 BrowserActionDragData drag_data(id, drag_index); |
| 182 drag_data.Write(owner_->profile(), data); |
| 183 } |
| 184 |
| 185 int BrowserActionOverflowMenuController::GetDragOperations( |
| 186 views::MenuItemView* sender) { |
| 187 return DragDropTypes::DRAG_MOVE; |
| 188 } |
| 189 |
| 190 BrowserActionView* BrowserActionOverflowMenuController::ViewForId( |
| 191 int id, size_t* index) { |
| 192 // The index of the view being dragged (GetCommand gives a 0-based index into |
| 193 // the overflow menu). |
| 194 size_t view_index = owner_->VisibleBrowserActions() + id; |
| 195 if (index) |
| 196 *index = view_index; |
| 197 return owner_->GetBrowserActionViewAt(view_index); |
| 198 } |
OLD | NEW |