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/bookmarks/bookmark_menu_controller_views.h" | 5 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h" |
6 | 6 |
7 #include "base/stl_util-inl.h" | 7 #include "base/stl_util-inl.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "chrome/browser/bookmarks/bookmark_model.h" | 9 #include "chrome/browser/bookmarks/bookmark_model.h" |
10 #include "chrome/browser/bookmarks/bookmark_node_data.h" | 10 #include "chrome/browser/bookmarks/bookmark_node_data.h" |
11 #include "chrome/browser/bookmarks/bookmark_utils.h" | 11 #include "chrome/browser/bookmarks/bookmark_utils.h" |
12 #include "chrome/browser/prefs/pref_service.h" | 12 #include "chrome/browser/prefs/pref_service.h" |
13 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
14 #include "chrome/browser/ui/browser.h" | |
15 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" | 14 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h" |
16 #include "chrome/browser/ui/views/event_utils.h" | 15 #include "chrome/browser/ui/views/event_utils.h" |
17 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
18 #include "content/browser/tab_contents/page_navigator.h" | 17 #include "content/browser/tab_contents/page_navigator.h" |
19 #include "content/browser/user_metrics.h" | 18 #include "content/browser/user_metrics.h" |
20 #include "content/common/page_transition_types.h" | 19 #include "content/common/page_transition_types.h" |
21 #include "grit/app_resources.h" | 20 #include "grit/app_resources.h" |
22 #include "grit/generated_resources.h" | 21 #include "grit/generated_resources.h" |
23 #include "grit/theme_resources.h" | 22 #include "grit/theme_resources.h" |
24 #include "ui/base/dragdrop/os_exchange_data.h" | 23 #include "ui/base/dragdrop/os_exchange_data.h" |
| 24 #include "ui/base/l10n/l10n_util.h" |
25 #include "ui/base/resource/resource_bundle.h" | 25 #include "ui/base/resource/resource_bundle.h" |
26 #include "views/controls/button/menu_button.h" | 26 #include "views/controls/button/menu_button.h" |
| 27 #include "views/controls/menu/menu_item_view.h" |
27 | 28 |
28 using views::MenuItemView; | 29 using views::MenuItemView; |
29 | 30 |
30 // Max width of a menu. There does not appear to be an OS value for this, yet | 31 // Max width of a menu. There does not appear to be an OS value for this, yet |
31 // both IE and FF restrict the max width of a menu. | 32 // both IE and FF restrict the max width of a menu. |
32 static const int kMaxMenuWidth = 400; | 33 static const int kMaxMenuWidth = 400; |
33 | 34 |
34 BookmarkMenuController::BookmarkMenuController(Browser* browser, | 35 BookmarkMenuDelegate::BookmarkMenuDelegate(Profile* profile, |
35 Profile* profile, | 36 PageNavigator* navigator, |
36 PageNavigator* navigator, | 37 gfx::NativeWindow parent, |
37 gfx::NativeWindow parent, | 38 int first_menu_id) |
38 const BookmarkNode* node, | 39 : profile_(profile), |
39 int start_child_index) | |
40 : browser_(browser), | |
41 profile_(profile), | |
42 page_navigator_(navigator), | 40 page_navigator_(navigator), |
43 parent_(parent), | 41 parent_(parent), |
44 node_(node), | |
45 menu_(NULL), | 42 menu_(NULL), |
46 observer_(NULL), | |
47 for_drop_(false), | 43 for_drop_(false), |
48 bookmark_bar_(NULL), | 44 next_menu_id_(first_menu_id), |
49 next_menu_id_(1) { | 45 real_delegate_(NULL), |
50 menu_ = CreateMenu(node, start_child_index); | 46 is_mutating_model_(false) { |
51 } | 47 } |
52 | 48 |
53 void BookmarkMenuController::RunMenuAt(BookmarkBarView* bookmark_bar, | 49 BookmarkMenuDelegate::~BookmarkMenuDelegate() { |
54 bool for_drop) { | 50 profile_->GetBookmarkModel()->RemoveObserver(this); |
55 bookmark_bar_ = bookmark_bar; | 51 STLDeleteValues(&node_to_menu_map_); |
56 views::MenuButton* menu_button = bookmark_bar_->GetMenuButtonForNode(node_); | |
57 DCHECK(menu_button); | |
58 MenuItemView::AnchorPosition anchor; | |
59 int start_index; | |
60 bookmark_bar_->GetAnchorPositionAndStartIndexForButton( | |
61 menu_button, &anchor, &start_index); | |
62 RunMenuAt(menu_button, anchor, for_drop); | |
63 } | 52 } |
64 | 53 |
65 void BookmarkMenuController::RunMenuAt( | 54 void BookmarkMenuDelegate::Init(views::MenuDelegate* real_delegate, |
66 views::MenuButton* button, | 55 MenuItemView* parent, |
67 MenuItemView::AnchorPosition position, | 56 const BookmarkNode* node, |
68 bool for_drop) { | 57 int start_child_index, |
69 gfx::Point screen_loc; | 58 ShowOptions show_options) { |
70 views::View::ConvertPointToScreen(button, &screen_loc); | |
71 // Subtract 1 from the height to make the popup flush with the button border. | |
72 gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(), | |
73 button->height() - 1); | |
74 for_drop_ = for_drop; | |
75 profile_->GetBookmarkModel()->AddObserver(this); | 59 profile_->GetBookmarkModel()->AddObserver(this); |
76 // The constructor creates the initial menu and that is all we should have | 60 real_delegate_ = real_delegate; |
77 // at this point. | 61 if (parent) { |
78 DCHECK(node_to_menu_map_.size() == 1); | 62 BuildMenu(node, start_child_index, parent, &next_menu_id_); |
79 if (for_drop) { | 63 if (show_options == SHOW_OTHER_FOLDER) |
80 menu_->RunMenuForDropAt(parent_, bounds, position); | 64 BuildOtherFolderMenu(parent, &next_menu_id_); |
81 } else { | 65 } else { |
82 menu_->RunMenuAt(parent_, button, bounds, position, false); | 66 menu_ = CreateMenu(node, start_child_index, show_options); |
83 delete this; | |
84 } | 67 } |
85 } | 68 } |
86 | 69 |
87 void BookmarkMenuController::Cancel() { | 70 void BookmarkMenuDelegate::SetActiveMenu(const BookmarkNode* node, |
88 menu_->Cancel(); | 71 int start_index) { |
| 72 if (!node_to_menu_map_[node]) |
| 73 CreateMenu(node, start_index, HIDE_OTHER_FOLDER); |
| 74 menu_ = node_to_menu_map_[node]; |
89 } | 75 } |
90 | 76 |
91 std::wstring BookmarkMenuController::GetTooltipText( | 77 std::wstring BookmarkMenuDelegate::GetTooltipText( |
92 int id, const gfx::Point& screen_loc) { | 78 int id, |
| 79 const gfx::Point& screen_loc) { |
93 DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); | 80 DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); |
94 | 81 |
95 const BookmarkNode* node = menu_id_to_node_map_[id]; | 82 const BookmarkNode* node = menu_id_to_node_map_[id]; |
96 if (node->type() == BookmarkNode::URL) | 83 if (node->type() == BookmarkNode::URL) |
97 return BookmarkBarView::CreateToolTipForURLAndTitle( | 84 return BookmarkBarView::CreateToolTipForURLAndTitle( |
98 screen_loc, node->GetURL(), UTF16ToWide(node->GetTitle()), profile_); | 85 screen_loc, node->GetURL(), UTF16ToWide(node->GetTitle()), profile_); |
99 return std::wstring(); | 86 return std::wstring(); |
100 } | 87 } |
101 | 88 |
102 bool BookmarkMenuController::IsTriggerableEvent(MenuItemView* view, | 89 bool BookmarkMenuDelegate::IsTriggerableEvent(views::MenuItemView* menu, |
103 const views::MouseEvent& e) { | 90 const views::MouseEvent& e) { |
104 return event_utils::IsPossibleDispositionEvent(e); | 91 return event_utils::IsPossibleDispositionEvent(e); |
105 } | 92 } |
106 | 93 |
107 void BookmarkMenuController::ExecuteCommand(int id, int mouse_event_flags) { | 94 void BookmarkMenuDelegate::ExecuteCommand(int id, int mouse_event_flags) { |
108 DCHECK(page_navigator_); | |
109 DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); | 95 DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); |
110 | 96 |
111 const BookmarkNode* node = menu_id_to_node_map_[id]; | 97 const BookmarkNode* node = menu_id_to_node_map_[id]; |
112 std::vector<const BookmarkNode*> selection; | 98 std::vector<const BookmarkNode*> selection; |
113 selection.push_back(node); | 99 selection.push_back(node); |
114 | 100 |
115 WindowOpenDisposition initial_disposition = | 101 WindowOpenDisposition initial_disposition = |
116 event_utils::DispositionFromEventFlags(mouse_event_flags); | 102 event_utils::DispositionFromEventFlags(mouse_event_flags); |
117 | 103 |
118 bookmark_utils::OpenAll(parent_, profile_, page_navigator_, selection, | 104 bookmark_utils::OpenAll(parent_, profile_, page_navigator_, selection, |
119 initial_disposition); | 105 initial_disposition); |
120 } | 106 } |
121 | 107 |
122 bool BookmarkMenuController::GetDropFormats( | 108 bool BookmarkMenuDelegate::GetDropFormats( |
123 MenuItemView* menu, | 109 MenuItemView* menu, |
124 int* formats, | 110 int* formats, |
125 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) { | 111 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) { |
126 *formats = ui::OSExchangeData::URL; | 112 *formats = ui::OSExchangeData::URL; |
127 custom_formats->insert(BookmarkNodeData::GetBookmarkCustomFormat()); | 113 custom_formats->insert(BookmarkNodeData::GetBookmarkCustomFormat()); |
128 return true; | 114 return true; |
129 } | 115 } |
130 | 116 |
131 bool BookmarkMenuController::AreDropTypesRequired(MenuItemView* menu) { | 117 bool BookmarkMenuDelegate::AreDropTypesRequired(MenuItemView* menu) { |
132 return true; | 118 return true; |
133 } | 119 } |
134 | 120 |
135 bool BookmarkMenuController::CanDrop(MenuItemView* menu, | 121 bool BookmarkMenuDelegate::CanDrop(MenuItemView* menu, |
136 const ui::OSExchangeData& data) { | 122 const ui::OSExchangeData& data) { |
137 // Only accept drops of 1 node, which is the case for all data dragged from | 123 // Only accept drops of 1 node, which is the case for all data dragged from |
138 // bookmark bar and menus. | 124 // bookmark bar and menus. |
139 | 125 |
140 if (!drop_data_.Read(data) || drop_data_.elements.size() != 1 || | 126 if (!drop_data_.Read(data) || drop_data_.elements.size() != 1 || |
141 !profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled)) | 127 !profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled)) |
142 return false; | 128 return false; |
143 | 129 |
144 if (drop_data_.has_single_url()) | 130 if (drop_data_.has_single_url()) |
145 return true; | 131 return true; |
146 | 132 |
147 const BookmarkNode* drag_node = drop_data_.GetFirstNode(profile_); | 133 const BookmarkNode* drag_node = drop_data_.GetFirstNode(profile_); |
148 if (!drag_node) { | 134 if (!drag_node) { |
149 // Dragging a folder from another profile, always accept. | 135 // Dragging a folder from another profile, always accept. |
150 return true; | 136 return true; |
151 } | 137 } |
152 | 138 |
153 // Drag originated from same profile and is not a URL. Only accept it if | 139 // Drag originated from same profile and is not a URL. Only accept it if |
154 // the dragged node is not a parent of the node menu represents. | 140 // the dragged node is not a parent of the node menu represents. |
| 141 if (menu_id_to_node_map_.find(menu->GetCommand()) == |
| 142 menu_id_to_node_map_.end()) { |
| 143 // If we don't know the menu assume its because we're embedded. We'll |
| 144 // figure out the real operation when GetDropOperation is invoked. |
| 145 return true; |
| 146 } |
155 const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; | 147 const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; |
156 DCHECK(drop_node); | 148 DCHECK(drop_node); |
157 while (drop_node && drop_node != drag_node) | 149 while (drop_node && drop_node != drag_node) |
158 drop_node = drop_node->parent(); | 150 drop_node = drop_node->parent(); |
159 return (drop_node == NULL); | 151 return (drop_node == NULL); |
160 } | 152 } |
161 | 153 |
162 int BookmarkMenuController::GetDropOperation( | 154 int BookmarkMenuDelegate::GetDropOperation( |
163 MenuItemView* item, | 155 MenuItemView* item, |
164 const views::DropTargetEvent& event, | 156 const views::DropTargetEvent& event, |
165 DropPosition* position) { | 157 views::MenuDelegate::DropPosition* position) { |
166 // Should only get here if we have drop data. | 158 // Should only get here if we have drop data. |
167 DCHECK(drop_data_.is_valid()); | 159 DCHECK(drop_data_.is_valid()); |
168 | 160 |
169 const BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()]; | 161 const BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()]; |
170 const BookmarkNode* drop_parent = node->parent(); | 162 const BookmarkNode* drop_parent = node->parent(); |
171 int index_to_drop_at = drop_parent->GetIndexOf(node); | 163 int index_to_drop_at = drop_parent->GetIndexOf(node); |
172 if (*position == DROP_AFTER) { | 164 if (*position == views::MenuDelegate::DROP_AFTER) { |
| 165 if (node == profile_->GetBookmarkModel()->other_node()) { |
| 166 // The other folder is shown after all bookmarks on the bookmark bar. |
| 167 // Dropping after the other folder makes no sense. |
| 168 *position = views::MenuDelegate::DROP_NONE; |
| 169 } |
173 index_to_drop_at++; | 170 index_to_drop_at++; |
174 } else if (*position == DROP_ON) { | 171 } else if (*position == views::MenuDelegate::DROP_ON) { |
175 drop_parent = node; | 172 drop_parent = node; |
176 index_to_drop_at = node->child_count(); | 173 index_to_drop_at = node->child_count(); |
177 } | 174 } |
178 DCHECK(drop_parent); | 175 DCHECK(drop_parent); |
179 return bookmark_utils::BookmarkDropOperation( | 176 return bookmark_utils::BookmarkDropOperation( |
180 profile_, event, drop_data_, drop_parent, index_to_drop_at); | 177 profile_, event, drop_data_, drop_parent, index_to_drop_at); |
181 } | 178 } |
182 | 179 |
183 int BookmarkMenuController::OnPerformDrop(MenuItemView* menu, | 180 int BookmarkMenuDelegate::OnPerformDrop( |
184 DropPosition position, | 181 MenuItemView* menu, |
185 const views::DropTargetEvent& event) { | 182 views::MenuDelegate::DropPosition position, |
| 183 const views::DropTargetEvent& event) { |
186 const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; | 184 const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; |
187 DCHECK(drop_node); | 185 DCHECK(drop_node); |
188 BookmarkModel* model = profile_->GetBookmarkModel(); | 186 BookmarkModel* model = profile_->GetBookmarkModel(); |
189 DCHECK(model); | 187 DCHECK(model); |
190 const BookmarkNode* drop_parent = drop_node->parent(); | 188 const BookmarkNode* drop_parent = drop_node->parent(); |
191 DCHECK(drop_parent); | 189 DCHECK(drop_parent); |
192 int index_to_drop_at = drop_parent->GetIndexOf(drop_node); | 190 int index_to_drop_at = drop_parent->GetIndexOf(drop_node); |
193 if (position == DROP_AFTER) { | 191 switch (position) { |
194 index_to_drop_at++; | 192 case views::MenuDelegate::DROP_AFTER: |
195 } else if (position == DROP_ON) { | 193 index_to_drop_at++; |
196 DCHECK(drop_node->is_folder()); | 194 break; |
197 drop_parent = drop_node; | 195 |
198 index_to_drop_at = drop_node->child_count(); | 196 case views::MenuDelegate::DROP_ON: |
| 197 DCHECK(drop_node->is_folder()); |
| 198 drop_parent = drop_node; |
| 199 index_to_drop_at = drop_node->child_count(); |
| 200 break; |
| 201 |
| 202 case views::MenuDelegate::DROP_BEFORE: |
| 203 if (drop_node == model->other_node()) { |
| 204 // This can happen with SHOW_OTHER_FOLDER. |
| 205 drop_parent = model->GetBookmarkBarNode(); |
| 206 index_to_drop_at = drop_parent->child_count(); |
| 207 } |
| 208 break; |
| 209 |
| 210 default: |
| 211 break; |
199 } | 212 } |
200 | 213 |
201 int result = bookmark_utils::PerformBookmarkDrop( | 214 int result = bookmark_utils::PerformBookmarkDrop( |
202 profile_, drop_data_, drop_parent, index_to_drop_at); | 215 profile_, drop_data_, drop_parent, index_to_drop_at); |
203 if (for_drop_) | |
204 delete this; | |
205 return result; | 216 return result; |
206 } | 217 } |
207 | 218 |
208 bool BookmarkMenuController::ShowContextMenu(MenuItemView* source, | 219 bool BookmarkMenuDelegate::ShowContextMenu(MenuItemView* source, |
209 int id, | 220 int id, |
210 const gfx::Point& p, | 221 const gfx::Point& p, |
211 bool is_mouse_gesture) { | 222 bool is_mouse_gesture) { |
212 DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); | 223 DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); |
213 std::vector<const BookmarkNode*> nodes; | 224 std::vector<const BookmarkNode*> nodes; |
214 nodes.push_back(menu_id_to_node_map_[id]); | 225 nodes.push_back(menu_id_to_node_map_[id]); |
215 context_menu_.reset( | 226 context_menu_.reset( |
216 new BookmarkContextMenu( | 227 new BookmarkContextMenu( |
217 parent_, | 228 parent_, |
218 profile_, | 229 profile_, |
219 page_navigator_, | 230 page_navigator_, |
220 nodes[0]->parent(), | 231 nodes[0]->parent(), |
221 nodes)); | 232 nodes)); |
222 context_menu_->set_observer(this); | 233 context_menu_->set_observer(this); |
223 context_menu_->RunMenuAt(p); | 234 context_menu_->RunMenuAt(p); |
224 context_menu_.reset(NULL); | 235 context_menu_.reset(NULL); |
225 return true; | 236 return true; |
226 } | 237 } |
227 | 238 |
228 void BookmarkMenuController::DropMenuClosed(MenuItemView* menu) { | 239 bool BookmarkMenuDelegate::CanDrag(MenuItemView* menu) { |
229 delete this; | 240 const BookmarkNode* node = menu_id_to_node_map_[menu->GetCommand()]; |
| 241 // Don't let users drag the other folder. |
| 242 return node->parent() != profile_->GetBookmarkModel()->root_node(); |
230 } | 243 } |
231 | 244 |
232 bool BookmarkMenuController::CanDrag(MenuItemView* menu) { | 245 void BookmarkMenuDelegate::WriteDragData(MenuItemView* sender, |
233 return true; | 246 ui::OSExchangeData* data) { |
234 } | |
235 | |
236 void BookmarkMenuController::WriteDragData(MenuItemView* sender, | |
237 ui::OSExchangeData* data) { | |
238 DCHECK(sender && data); | 247 DCHECK(sender && data); |
239 | 248 |
240 UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragFromFolder")); | 249 UserMetrics::RecordAction(UserMetricsAction("BookmarkBar_DragFromFolder")); |
241 | 250 |
242 BookmarkNodeData drag_data(menu_id_to_node_map_[sender->GetCommand()]); | 251 BookmarkNodeData drag_data(menu_id_to_node_map_[sender->GetCommand()]); |
243 drag_data.Write(profile_, data); | 252 drag_data.Write(profile_, data); |
244 } | 253 } |
245 | 254 |
246 int BookmarkMenuController::GetDragOperations(MenuItemView* sender) { | 255 int BookmarkMenuDelegate::GetDragOperations(MenuItemView* sender) { |
247 return bookmark_utils::BookmarkDragOperation(profile_, | 256 return bookmark_utils::BookmarkDragOperation( |
248 menu_id_to_node_map_[sender->GetCommand()]); | 257 profile_, menu_id_to_node_map_[sender->GetCommand()]); |
249 } | 258 } |
250 | 259 |
251 views::MenuItemView* BookmarkMenuController::GetSiblingMenu( | 260 int BookmarkMenuDelegate::GetMaxWidthForMenu(MenuItemView* menu) { |
252 views::MenuItemView* menu, | |
253 const gfx::Point& screen_point, | |
254 views::MenuItemView::AnchorPosition* anchor, | |
255 bool* has_mnemonics, | |
256 views::MenuButton** button) { | |
257 if (!bookmark_bar_ || for_drop_) | |
258 return NULL; | |
259 gfx::Point bookmark_bar_loc(screen_point); | |
260 views::View::ConvertPointToView(NULL, bookmark_bar_, &bookmark_bar_loc); | |
261 int start_index; | |
262 const BookmarkNode* node = | |
263 bookmark_bar_->GetNodeForButtonAt(bookmark_bar_loc, &start_index); | |
264 if (!node || !node->is_folder()) | |
265 return NULL; | |
266 | |
267 MenuItemView* alt_menu = node_to_menu_map_[node]; | |
268 if (!alt_menu) | |
269 alt_menu = CreateMenu(node, start_index); | |
270 | |
271 menu_ = alt_menu; | |
272 | |
273 *button = bookmark_bar_->GetMenuButtonForNode(node); | |
274 bookmark_bar_->GetAnchorPositionAndStartIndexForButton( | |
275 *button, anchor, &start_index); | |
276 *has_mnemonics = false; | |
277 return alt_menu; | |
278 } | |
279 | |
280 int BookmarkMenuController::GetMaxWidthForMenu(MenuItemView* view) { | |
281 return kMaxMenuWidth; | 261 return kMaxMenuWidth; |
282 } | 262 } |
283 | 263 |
284 void BookmarkMenuController::BookmarkModelChanged() { | 264 void BookmarkMenuDelegate::BookmarkModelChanged() { |
285 menu_->Cancel(); | |
286 } | 265 } |
287 | 266 |
288 void BookmarkMenuController::BookmarkNodeFaviconLoaded( | 267 void BookmarkMenuDelegate::BookmarkNodeFaviconLoaded( |
289 BookmarkModel* model, const BookmarkNode* node) { | 268 BookmarkModel* model, const BookmarkNode* node) { |
290 NodeToMenuIDMap::iterator menu_pair = node_to_menu_id_map_.find(node); | 269 NodeToMenuIDMap::iterator menu_pair = node_to_menu_id_map_.find(node); |
291 if (menu_pair == node_to_menu_id_map_.end()) | 270 if (menu_pair == node_to_menu_id_map_.end()) |
292 return; // We're not showing a menu item for the node. | 271 return; // We're not showing a menu item for the node. |
293 | 272 |
294 // Iterate through the menus looking for the menu containing node. | 273 // Iterate through the menus looking for the menu containing node. |
295 for (NodeToMenuMap::iterator i = node_to_menu_map_.begin(); | 274 for (NodeToMenuMap::iterator i = node_to_menu_map_.begin(); |
296 i != node_to_menu_map_.end(); ++i) { | 275 i != node_to_menu_map_.end(); ++i) { |
297 MenuItemView* menu_item = i->second->GetMenuItemByID(menu_pair->second); | 276 MenuItemView* menu_item = i->second->GetMenuItemByID(menu_pair->second); |
298 if (menu_item) { | 277 if (menu_item) { |
299 menu_item->SetIcon(model->GetFavicon(node)); | 278 menu_item->SetIcon(model->GetFavicon(node)); |
300 return; | 279 return; |
301 } | 280 } |
302 } | 281 } |
303 } | 282 } |
304 | 283 |
305 void BookmarkMenuController::WillRemoveBookmarks( | 284 void BookmarkMenuDelegate::WillRemoveBookmarks( |
306 const std::vector<const BookmarkNode*>& bookmarks) { | 285 const std::vector<const BookmarkNode*>& bookmarks) { |
| 286 DCHECK(!is_mutating_model_); |
| 287 is_mutating_model_ = true; |
307 std::set<MenuItemView*> removed_menus; | 288 std::set<MenuItemView*> removed_menus; |
308 | |
309 WillRemoveBookmarksImpl(bookmarks, &removed_menus); | 289 WillRemoveBookmarksImpl(bookmarks, &removed_menus); |
310 | |
311 STLDeleteElements(&removed_menus); | 290 STLDeleteElements(&removed_menus); |
312 } | 291 } |
313 | 292 |
314 void BookmarkMenuController::DidRemoveBookmarks() { | 293 void BookmarkMenuDelegate::DidRemoveBookmarks() { |
| 294 // Balances remove in WillRemoveBookmarksImpl. |
315 profile_->GetBookmarkModel()->AddObserver(this); | 295 profile_->GetBookmarkModel()->AddObserver(this); |
| 296 DCHECK(is_mutating_model_); |
| 297 is_mutating_model_ = false; |
316 } | 298 } |
317 | 299 |
318 MenuItemView* BookmarkMenuController::CreateMenu(const BookmarkNode* parent, | 300 MenuItemView* BookmarkMenuDelegate::CreateMenu(const BookmarkNode* parent, |
319 int start_child_index) { | 301 int start_child_index, |
320 MenuItemView* menu = new MenuItemView(this); | 302 ShowOptions show_options) { |
| 303 MenuItemView* menu = new MenuItemView(real_delegate_); |
321 menu->SetCommand(next_menu_id_++); | 304 menu->SetCommand(next_menu_id_++); |
322 menu_id_to_node_map_[menu->GetCommand()] = parent; | 305 menu_id_to_node_map_[menu->GetCommand()] = parent; |
323 menu->set_has_icons(true); | 306 menu->set_has_icons(true); |
324 BuildMenu(parent, start_child_index, menu, &next_menu_id_); | 307 BuildMenu(parent, start_child_index, menu, &next_menu_id_); |
| 308 if (show_options == SHOW_OTHER_FOLDER) |
| 309 BuildOtherFolderMenu(menu, &next_menu_id_); |
325 node_to_menu_map_[parent] = menu; | 310 node_to_menu_map_[parent] = menu; |
326 return menu; | 311 return menu; |
327 } | 312 } |
328 | 313 |
329 void BookmarkMenuController::BuildMenu(const BookmarkNode* parent, | 314 void BookmarkMenuDelegate::BuildOtherFolderMenu( |
330 int start_child_index, | 315 MenuItemView* menu, int* next_menu_id) { |
331 MenuItemView* menu, | 316 const BookmarkNode* other_folder = profile_->GetBookmarkModel()->other_node(); |
332 int* next_menu_id) { | 317 int id = *next_menu_id; |
| 318 (*next_menu_id)++; |
| 319 SkBitmap* folder_icon = ResourceBundle::GetSharedInstance(). |
| 320 GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER); |
| 321 MenuItemView* submenu = menu->AppendSubMenuWithIcon( |
| 322 id, UTF16ToWide( |
| 323 l10n_util::GetStringUTF16(IDS_BOOMARK_BAR_OTHER_BOOKMARKED)), |
| 324 *folder_icon); |
| 325 BuildMenu(other_folder, 0, submenu, next_menu_id); |
| 326 menu_id_to_node_map_[id] = other_folder; |
| 327 } |
| 328 |
| 329 void BookmarkMenuDelegate::BuildMenu(const BookmarkNode* parent, |
| 330 int start_child_index, |
| 331 MenuItemView* menu, |
| 332 int* next_menu_id) { |
333 DCHECK(!parent->child_count() || | 333 DCHECK(!parent->child_count() || |
334 start_child_index < parent->child_count()); | 334 start_child_index < parent->child_count()); |
335 for (int i = start_child_index; i < parent->child_count(); ++i) { | 335 for (int i = start_child_index; i < parent->child_count(); ++i) { |
336 const BookmarkNode* node = parent->GetChild(i); | 336 const BookmarkNode* node = parent->GetChild(i); |
337 int id = *next_menu_id; | 337 int id = *next_menu_id; |
338 | 338 |
339 (*next_menu_id)++; | 339 (*next_menu_id)++; |
340 if (node->is_url()) { | 340 if (node->is_url()) { |
341 SkBitmap icon = profile_->GetBookmarkModel()->GetFavicon(node); | 341 SkBitmap icon = profile_->GetBookmarkModel()->GetFavicon(node); |
342 if (icon.width() == 0) { | 342 if (icon.width() == 0) { |
343 icon = *ResourceBundle::GetSharedInstance(). | 343 icon = *ResourceBundle::GetSharedInstance(). |
344 GetBitmapNamed(IDR_DEFAULT_FAVICON); | 344 GetBitmapNamed(IDR_DEFAULT_FAVICON); |
345 } | 345 } |
346 menu->AppendMenuItemWithIcon(id, UTF16ToWide(node->GetTitle()), icon); | 346 menu->AppendMenuItemWithIcon(id, UTF16ToWide(node->GetTitle()), icon); |
347 node_to_menu_id_map_[node] = id; | 347 node_to_menu_id_map_[node] = id; |
348 } else if (node->is_folder()) { | 348 } else if (node->is_folder()) { |
349 SkBitmap* folder_icon = ResourceBundle::GetSharedInstance(). | 349 SkBitmap* folder_icon = ResourceBundle::GetSharedInstance(). |
350 GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER); | 350 GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER); |
351 MenuItemView* submenu = menu->AppendSubMenuWithIcon(id, | 351 MenuItemView* submenu = menu->AppendSubMenuWithIcon( |
352 UTF16ToWide(node->GetTitle()), *folder_icon); | 352 id, UTF16ToWide(node->GetTitle()), *folder_icon); |
353 node_to_menu_id_map_[node] = id; | 353 node_to_menu_id_map_[node] = id; |
354 BuildMenu(node, 0, submenu, next_menu_id); | 354 BuildMenu(node, 0, submenu, next_menu_id); |
355 } else { | 355 } else { |
356 NOTREACHED(); | 356 NOTREACHED(); |
357 } | 357 } |
358 menu_id_to_node_map_[id] = node; | 358 menu_id_to_node_map_[id] = node; |
359 } | 359 } |
360 } | 360 } |
361 | 361 |
362 BookmarkMenuController::~BookmarkMenuController() { | 362 MenuItemView* BookmarkMenuDelegate::GetMenuByID(int id) { |
363 profile_->GetBookmarkModel()->RemoveObserver(this); | |
364 if (observer_) | |
365 observer_->BookmarkMenuDeleted(this); | |
366 STLDeleteValues(&node_to_menu_map_); | |
367 } | |
368 | |
369 MenuItemView* BookmarkMenuController::GetMenuByID(int id) { | |
370 for (NodeToMenuMap::const_iterator i = node_to_menu_map_.begin(); | 363 for (NodeToMenuMap::const_iterator i = node_to_menu_map_.begin(); |
371 i != node_to_menu_map_.end(); ++i) { | 364 i != node_to_menu_map_.end(); ++i) { |
372 MenuItemView* menu = i->second->GetMenuItemByID(id); | 365 MenuItemView* menu = i->second->GetMenuItemByID(id); |
373 if (menu) | 366 if (menu) |
374 return menu; | 367 return menu; |
375 } | 368 } |
376 return NULL; | 369 return NULL; |
377 } | 370 } |
378 | 371 |
379 void BookmarkMenuController::WillRemoveBookmarksImpl( | 372 void BookmarkMenuDelegate::WillRemoveBookmarksImpl( |
380 const std::vector<const BookmarkNode*>& bookmarks, | 373 const std::vector<const BookmarkNode*>& bookmarks, |
381 std::set<views::MenuItemView*>* removed_menus) { | 374 std::set<views::MenuItemView*>* removed_menus) { |
382 // Remove the observer so that when the remove happens we don't prematurely | 375 // Remove the observer so that when the remove happens we don't prematurely |
383 // cancel the menu. | 376 // cancel the menu. The observer ias added back in DidRemoveBookmarks. |
384 profile_->GetBookmarkModel()->RemoveObserver(this); | 377 profile_->GetBookmarkModel()->RemoveObserver(this); |
385 | 378 |
386 // Remove the menu items. | 379 // Remove the menu items. |
387 std::set<MenuItemView*> changed_parent_menus; | 380 std::set<MenuItemView*> changed_parent_menus; |
388 for (std::vector<const BookmarkNode*>::const_iterator i = bookmarks.begin(); | 381 for (std::vector<const BookmarkNode*>::const_iterator i = bookmarks.begin(); |
389 i != bookmarks.end(); ++i) { | 382 i != bookmarks.end(); ++i) { |
390 NodeToMenuIDMap::iterator node_to_menu = node_to_menu_id_map_.find(*i); | 383 NodeToMenuIDMap::iterator node_to_menu = node_to_menu_id_map_.find(*i); |
391 if (node_to_menu != node_to_menu_id_map_.end()) { | 384 if (node_to_menu != node_to_menu_id_map_.end()) { |
392 MenuItemView* menu = GetMenuByID(node_to_menu->second); | 385 MenuItemView* menu = GetMenuByID(node_to_menu->second); |
393 DCHECK(menu); // If there an entry in node_to_menu_id_map_, there should | 386 DCHECK(menu); // If there an entry in node_to_menu_id_map_, there should |
394 // be a menu. | 387 // be a menu. |
395 removed_menus->insert(menu); | 388 removed_menus->insert(menu); |
396 changed_parent_menus.insert(menu->GetParentMenuItem()); | 389 changed_parent_menus.insert(menu->GetParentMenuItem()); |
397 menu->parent()->RemoveChildView(menu); | 390 menu->parent()->RemoveChildView(menu); |
398 node_to_menu_id_map_.erase(node_to_menu); | 391 node_to_menu_id_map_.erase(node_to_menu); |
399 } | 392 } |
400 } | 393 } |
401 | 394 |
402 // All the bookmarks in |bookmarks| should have the same parent. It's possible | 395 // All the bookmarks in |bookmarks| should have the same parent. It's possible |
403 // to support different parents, but this would need to prune any nodes whose | 396 // to support different parents, but this would need to prune any nodes whose |
404 // parent has been removed. As all nodes currently have the same parent, there | 397 // parent has been removed. As all nodes currently have the same parent, there |
(...skipping 16 matching lines...) Expand all Loading... |
421 break; | 414 break; |
422 } | 415 } |
423 } | 416 } |
424 if (ancestor_removed) { | 417 if (ancestor_removed) { |
425 node_to_menu_id_map_.erase(i++); | 418 node_to_menu_id_map_.erase(i++); |
426 } else { | 419 } else { |
427 ++i; | 420 ++i; |
428 } | 421 } |
429 } | 422 } |
430 } | 423 } |
OLD | NEW |