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