Home | History | Annotate | Download | only in bookmarks
      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 
     33 using base::UserMetricsAction;
     34 using content::PageNavigator;
     35 
     36 BookmarkContextMenuController::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 
     60 BookmarkContextMenuController::~BookmarkContextMenuController() {
     61   if (model_)
     62     model_->RemoveObserver(this);
     63 }
     64 
     65 void 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 
    120 void BookmarkContextMenuController::AddItem(int id, int localization_id) {
    121   menu_model_->AddItemWithStringId(id, localization_id);
    122 }
    123 
    124 void BookmarkContextMenuController::AddSeparator() {
    125   menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
    126 }
    127 
    128 void BookmarkContextMenuController::AddCheckboxItem(int id,
    129                                                     int localization_id) {
    130   menu_model_->AddCheckItemWithStringId(id, localization_id);
    131 }
    132 
    133 void 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 
    303 bool 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 
    310 base::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 
    331 bool 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 
    343 bool 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 
    414 bool 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 
    426 bool BookmarkContextMenuController::GetAcceleratorForCommandId(
    427     int command_id,
    428     ui::Accelerator* accelerator) {
    429   return false;
    430 }
    431 
    432 void BookmarkContextMenuController::BookmarkModelChanged() {
    433   if (delegate_)
    434     delegate_->CloseMenu();
    435 }
    436