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 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/bookmarks/bookmark_context_menu_controller.h" 6 7#include "base/command_line.h" 8#include "base/compiler_specific.h" 9#include "base/prefs/pref_service.h" 10#include "chrome/app/chrome_command_ids.h" 11#include "chrome/browser/bookmarks/bookmark_model_factory.h" 12#include "chrome/browser/bookmarks/chrome_bookmark_client.h" 13#include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h" 14#include "chrome/browser/prefs/incognito_mode_prefs.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/browser/ui/bookmarks/bookmark_editor.h" 17#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 18#include "chrome/browser/ui/browser.h" 19#include "chrome/browser/ui/chrome_pages.h" 20#include "chrome/browser/ui/tabs/tab_strip_model.h" 21#include "chrome/browser/undo/bookmark_undo_service.h" 22#include "chrome/browser/undo/bookmark_undo_service_factory.h" 23#include "chrome/common/chrome_switches.h" 24#include "chrome/common/pref_names.h" 25#include "chrome/grit/generated_resources.h" 26#include "components/bookmarks/browser/bookmark_client.h" 27#include "components/bookmarks/browser/bookmark_model.h" 28#include "components/bookmarks/browser/bookmark_utils.h" 29#include "content/public/browser/page_navigator.h" 30#include "content/public/browser/user_metrics.h" 31#include "ui/base/l10n/l10n_util.h" 32 33using base::UserMetricsAction; 34using content::PageNavigator; 35 36BookmarkContextMenuController::BookmarkContextMenuController( 37 gfx::NativeWindow parent_window, 38 BookmarkContextMenuControllerDelegate* delegate, 39 Browser* browser, 40 Profile* profile, 41 PageNavigator* navigator, 42 const BookmarkNode* parent, 43 const std::vector<const BookmarkNode*>& selection) 44 : parent_window_(parent_window), 45 delegate_(delegate), 46 browser_(browser), 47 profile_(profile), 48 navigator_(navigator), 49 parent_(parent), 50 selection_(selection), 51 model_(BookmarkModelFactory::GetForProfile(profile)) { 52 DCHECK(profile_); 53 DCHECK(model_->loaded()); 54 menu_model_.reset(new ui::SimpleMenuModel(this)); 55 model_->AddObserver(this); 56 57 BuildMenu(); 58} 59 60BookmarkContextMenuController::~BookmarkContextMenuController() { 61 if (model_) 62 model_->RemoveObserver(this); 63} 64 65void BookmarkContextMenuController::BuildMenu() { 66 if (selection_.size() == 1 && selection_[0]->is_url()) { 67 AddItem(IDC_BOOKMARK_BAR_OPEN_ALL, 68 IDS_BOOKMARK_BAR_OPEN_IN_NEW_TAB); 69 AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW, 70 IDS_BOOKMARK_BAR_OPEN_IN_NEW_WINDOW); 71 AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO, 72 IDS_BOOKMARK_BAR_OPEN_INCOGNITO); 73 } else { 74 AddItem(IDC_BOOKMARK_BAR_OPEN_ALL, IDS_BOOKMARK_BAR_OPEN_ALL); 75 AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW, 76 IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW); 77 AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO, 78 IDS_BOOKMARK_BAR_OPEN_ALL_INCOGNITO); 79 } 80 81 AddSeparator(); 82 if (selection_.size() == 1 && selection_[0]->is_folder()) { 83 AddItem(IDC_BOOKMARK_BAR_RENAME_FOLDER, IDS_BOOKMARK_BAR_RENAME_FOLDER); 84 } else { 85 AddItem(IDC_BOOKMARK_BAR_EDIT, IDS_BOOKMARK_BAR_EDIT); 86 } 87 88 AddSeparator(); 89 AddItem(IDC_CUT, IDS_CUT); 90 AddItem(IDC_COPY, IDS_COPY); 91 AddItem(IDC_PASTE, IDS_PASTE); 92 93 AddSeparator(); 94 AddItem(IDC_BOOKMARK_BAR_REMOVE, IDS_BOOKMARK_BAR_REMOVE); 95 if (CommandLine::ForCurrentProcess()->HasSwitch( 96 switches::kEnableBookmarkUndo)) { 97 AddItem(IDC_BOOKMARK_BAR_UNDO, IDS_BOOKMARK_BAR_UNDO); 98 AddItem(IDC_BOOKMARK_BAR_REDO, IDS_BOOKMARK_BAR_REDO); 99 } 100 101 AddSeparator(); 102 AddItem(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK, IDS_BOOKMARK_BAR_ADD_NEW_BOOKMARK); 103 AddItem(IDC_BOOKMARK_BAR_NEW_FOLDER, IDS_BOOKMARK_BAR_NEW_FOLDER); 104 105 AddSeparator(); 106 AddItem(IDC_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER); 107 // Use the native host desktop type in tests. 108 if (chrome::IsAppsShortcutEnabled( 109 profile_, 110 browser_ ? browser_->host_desktop_type() 111 : chrome::HOST_DESKTOP_TYPE_NATIVE)) { 112 AddCheckboxItem(IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT, 113 IDS_BOOKMARK_BAR_SHOW_APPS_SHORTCUT); 114 } 115 AddCheckboxItem(IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS, 116 IDS_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS_DEFAULT_NAME); 117 AddCheckboxItem(IDC_BOOKMARK_BAR_ALWAYS_SHOW, IDS_SHOW_BOOKMARK_BAR); 118} 119 120void BookmarkContextMenuController::AddItem(int id, int localization_id) { 121 menu_model_->AddItemWithStringId(id, localization_id); 122} 123 124void BookmarkContextMenuController::AddSeparator() { 125 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 126} 127 128void BookmarkContextMenuController::AddCheckboxItem(int id, 129 int localization_id) { 130 menu_model_->AddCheckItemWithStringId(id, localization_id); 131} 132 133void BookmarkContextMenuController::ExecuteCommand(int id, int event_flags) { 134 if (delegate_) 135 delegate_->WillExecuteCommand(id, selection_); 136 137 switch (id) { 138 case IDC_BOOKMARK_BAR_OPEN_ALL: 139 case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO: 140 case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW: { 141 WindowOpenDisposition initial_disposition; 142 if (id == IDC_BOOKMARK_BAR_OPEN_ALL) { 143 initial_disposition = NEW_BACKGROUND_TAB; 144 content::RecordAction( 145 UserMetricsAction("BookmarkBar_ContextMenu_OpenAll")); 146 } else if (id == IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW) { 147 initial_disposition = NEW_WINDOW; 148 content::RecordAction( 149 UserMetricsAction("BookmarkBar_ContextMenu_OpenAllInNewWindow")); 150 } else { 151 initial_disposition = OFF_THE_RECORD; 152 content::RecordAction( 153 UserMetricsAction("BookmarkBar_ContextMenu_OpenAllIncognito")); 154 } 155 chrome::OpenAll(parent_window_, navigator_, selection_, 156 initial_disposition, profile_); 157 break; 158 } 159 160 case IDC_BOOKMARK_BAR_RENAME_FOLDER: 161 case IDC_BOOKMARK_BAR_EDIT: 162 content::RecordAction( 163 UserMetricsAction("BookmarkBar_ContextMenu_Edit")); 164 165 if (selection_.size() != 1) { 166 NOTREACHED(); 167 break; 168 } 169 170 BookmarkEditor::Show( 171 parent_window_, 172 profile_, 173 BookmarkEditor::EditDetails::EditNode(selection_[0]), 174 selection_[0]->is_url() ? BookmarkEditor::SHOW_TREE : 175 BookmarkEditor::NO_TREE); 176 break; 177 178 case IDC_BOOKMARK_BAR_UNDO: { 179 content::RecordAction( 180 UserMetricsAction("BookmarkBar_ContextMenu_Undo")); 181 BookmarkUndoServiceFactory::GetForProfile(profile_)->undo_manager()-> 182 Undo(); 183 break; 184 } 185 186 case IDC_BOOKMARK_BAR_REDO: { 187 content::RecordAction( 188 UserMetricsAction("BookmarkBar_ContextMenu_Redo")); 189 BookmarkUndoServiceFactory::GetForProfile(profile_)->undo_manager()-> 190 Redo(); 191 break; 192 } 193 194 case IDC_BOOKMARK_BAR_REMOVE: { 195 content::RecordAction( 196 UserMetricsAction("BookmarkBar_ContextMenu_Remove")); 197 198 for (size_t i = 0; i < selection_.size(); ++i) { 199 int index = selection_[i]->parent()->GetIndexOf(selection_[i]); 200 if (index > -1) 201 model_->Remove(selection_[i]->parent(), index); 202 } 203 selection_.clear(); 204 break; 205 } 206 207 case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK: { 208 content::RecordAction( 209 UserMetricsAction("BookmarkBar_ContextMenu_Add")); 210 211 int index; 212 const BookmarkNode* parent = 213 bookmarks::GetParentForNewNodes(parent_, selection_, &index); 214 GURL url; 215 base::string16 title; 216 chrome::GetURLAndTitleToBookmark( 217 browser_->tab_strip_model()->GetActiveWebContents(), 218 &url, &title); 219 BookmarkEditor::Show(parent_window_, 220 profile_, 221 BookmarkEditor::EditDetails::AddNodeInFolder( 222 parent, index, url, title), 223 BookmarkEditor::SHOW_TREE); 224 break; 225 } 226 227 case IDC_BOOKMARK_BAR_NEW_FOLDER: { 228 content::RecordAction( 229 UserMetricsAction("BookmarkBar_ContextMenu_NewFolder")); 230 231 int index; 232 const BookmarkNode* parent = 233 bookmarks::GetParentForNewNodes(parent_, selection_, &index); 234 BookmarkEditor::Show( 235 parent_window_, 236 profile_, 237 BookmarkEditor::EditDetails::AddFolder(parent, index), 238 BookmarkEditor::SHOW_TREE); 239 break; 240 } 241 242 case IDC_BOOKMARK_BAR_ALWAYS_SHOW: 243 chrome::ToggleBookmarkBarWhenVisible(profile_); 244 break; 245 246 case IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT: { 247 PrefService* prefs = profile_->GetPrefs(); 248 prefs->SetBoolean( 249 bookmarks::prefs::kShowAppsShortcutInBookmarkBar, 250 !prefs->GetBoolean(bookmarks::prefs::kShowAppsShortcutInBookmarkBar)); 251 break; 252 } 253 254 case IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS: { 255 PrefService* prefs = profile_->GetPrefs(); 256 prefs->SetBoolean( 257 bookmarks::prefs::kShowManagedBookmarksInBookmarkBar, 258 !prefs->GetBoolean( 259 bookmarks::prefs::kShowManagedBookmarksInBookmarkBar)); 260 break; 261 } 262 263 case IDC_BOOKMARK_MANAGER: { 264 content::RecordAction(UserMetricsAction("ShowBookmarkManager")); 265 if (selection_.size() != 1) 266 chrome::ShowBookmarkManager(browser_); 267 else if (selection_[0]->is_folder()) 268 chrome::ShowBookmarkManagerForNode(browser_, selection_[0]->id()); 269 else if (parent_) 270 chrome::ShowBookmarkManagerForNode(browser_, parent_->id()); 271 else 272 chrome::ShowBookmarkManager(browser_); 273 break; 274 } 275 276 case IDC_CUT: 277 bookmarks::CopyToClipboard(model_, selection_, true); 278 break; 279 280 case IDC_COPY: 281 bookmarks::CopyToClipboard(model_, selection_, false); 282 break; 283 284 case IDC_PASTE: { 285 int index; 286 const BookmarkNode* paste_target = 287 bookmarks::GetParentForNewNodes(parent_, selection_, &index); 288 if (!paste_target) 289 return; 290 291 bookmarks::PasteFromClipboard(model_, paste_target, index); 292 break; 293 } 294 295 default: 296 NOTREACHED(); 297 } 298 299 if (delegate_) 300 delegate_->DidExecuteCommand(id); 301} 302 303bool BookmarkContextMenuController::IsItemForCommandIdDynamic(int command_id) 304 const { 305 return command_id == IDC_BOOKMARK_BAR_UNDO || 306 command_id == IDC_BOOKMARK_BAR_REDO || 307 command_id == IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS; 308} 309 310base::string16 BookmarkContextMenuController::GetLabelForCommandId( 311 int command_id) const { 312 if (command_id == IDC_BOOKMARK_BAR_UNDO) { 313 return BookmarkUndoServiceFactory::GetForProfile(profile_)-> 314 undo_manager()->GetUndoLabel(); 315 } 316 if (command_id == IDC_BOOKMARK_BAR_REDO) { 317 return BookmarkUndoServiceFactory::GetForProfile(profile_)-> 318 undo_manager()->GetRedoLabel(); 319 } 320 if (command_id == IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS) { 321 ChromeBookmarkClient* client = 322 ChromeBookmarkClientFactory::GetForProfile(profile_); 323 return l10n_util::GetStringFUTF16(IDS_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS, 324 client->managed_node()->GetTitle()); 325 } 326 327 NOTREACHED(); 328 return base::string16(); 329} 330 331bool BookmarkContextMenuController::IsCommandIdChecked(int command_id) const { 332 PrefService* prefs = profile_->GetPrefs(); 333 if (command_id == IDC_BOOKMARK_BAR_ALWAYS_SHOW) 334 return prefs->GetBoolean(bookmarks::prefs::kShowBookmarkBar); 335 if (command_id == IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS) 336 return prefs->GetBoolean( 337 bookmarks::prefs::kShowManagedBookmarksInBookmarkBar); 338 339 DCHECK_EQ(IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT, command_id); 340 return prefs->GetBoolean(bookmarks::prefs::kShowAppsShortcutInBookmarkBar); 341} 342 343bool BookmarkContextMenuController::IsCommandIdEnabled(int command_id) const { 344 PrefService* prefs = profile_->GetPrefs(); 345 346 bool is_root_node = selection_.size() == 1 && 347 selection_[0]->parent() == model_->root_node(); 348 bool can_edit = prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled) && 349 bookmarks::CanAllBeEditedByUser(model_->client(), selection_); 350 IncognitoModePrefs::Availability incognito_avail = 351 IncognitoModePrefs::GetAvailability(prefs); 352 353 switch (command_id) { 354 case IDC_BOOKMARK_BAR_OPEN_INCOGNITO: 355 return !profile_->IsOffTheRecord() && 356 incognito_avail != IncognitoModePrefs::DISABLED; 357 358 case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO: 359 return chrome::HasBookmarkURLsAllowedInIncognitoMode(selection_, profile_) 360 && 361 !profile_->IsOffTheRecord() && 362 incognito_avail != IncognitoModePrefs::DISABLED; 363 364 case IDC_BOOKMARK_BAR_OPEN_ALL: 365 return chrome::HasBookmarkURLs(selection_); 366 case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW: 367 return chrome::HasBookmarkURLs(selection_) && 368 incognito_avail != IncognitoModePrefs::FORCED; 369 370 case IDC_BOOKMARK_BAR_RENAME_FOLDER: 371 case IDC_BOOKMARK_BAR_EDIT: 372 return selection_.size() == 1 && !is_root_node && can_edit; 373 374 case IDC_BOOKMARK_BAR_UNDO: 375 return can_edit && 376 BookmarkUndoServiceFactory::GetForProfile(profile_)-> 377 undo_manager()->undo_count() > 0; 378 379 case IDC_BOOKMARK_BAR_REDO: 380 return can_edit && 381 BookmarkUndoServiceFactory::GetForProfile(profile_)-> 382 undo_manager()->redo_count() > 0; 383 384 case IDC_BOOKMARK_BAR_REMOVE: 385 return !selection_.empty() && !is_root_node && can_edit; 386 387 case IDC_BOOKMARK_BAR_NEW_FOLDER: 388 case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK: 389 return can_edit && model_->client()->CanBeEditedByUser(parent_) && 390 bookmarks::GetParentForNewNodes(parent_, selection_, NULL) != NULL; 391 392 case IDC_BOOKMARK_BAR_ALWAYS_SHOW: 393 return !prefs->IsManagedPreference(bookmarks::prefs::kShowBookmarkBar); 394 395 case IDC_BOOKMARK_BAR_SHOW_APPS_SHORTCUT: 396 return !prefs->IsManagedPreference( 397 bookmarks::prefs::kShowAppsShortcutInBookmarkBar); 398 399 case IDC_COPY: 400 case IDC_CUT: 401 return !selection_.empty() && !is_root_node && 402 (command_id == IDC_COPY || can_edit); 403 404 case IDC_PASTE: 405 // Paste to selection from the Bookmark Bar, to parent_ everywhere else 406 return can_edit && 407 ((!selection_.empty() && 408 bookmarks::CanPasteFromClipboard(model_, selection_[0])) || 409 bookmarks::CanPasteFromClipboard(model_, parent_)); 410 } 411 return true; 412} 413 414bool BookmarkContextMenuController::IsCommandIdVisible(int command_id) const { 415 if (command_id == IDC_BOOKMARK_BAR_SHOW_MANAGED_BOOKMARKS) { 416 // The option to hide the Managed Bookmarks folder is only available if 417 // there are any managed bookmarks configured at all. 418 ChromeBookmarkClient* client = 419 ChromeBookmarkClientFactory::GetForProfile(profile_); 420 return !client->managed_node()->empty(); 421 } 422 423 return true; 424} 425 426bool BookmarkContextMenuController::GetAcceleratorForCommandId( 427 int command_id, 428 ui::Accelerator* accelerator) { 429 return false; 430} 431 432void BookmarkContextMenuController::BookmarkModelChanged() { 433 if (delegate_) 434 delegate_->CloseMenu(); 435} 436