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
3// found in the LICENSE file.
4
5#include "chrome/browser/bookmarks/bookmark_context_menu_controller.h"
6
7#include "base/compiler_specific.h"
8#include "chrome/app/chrome_command_ids.h"
9#include "chrome/browser/bookmarks/bookmark_editor.h"
10#include "chrome/browser/bookmarks/bookmark_folder_editor_controller.h"
11#include "chrome/browser/bookmarks/bookmark_model.h"
12#include "chrome/browser/bookmarks/bookmark_utils.h"
13#include "chrome/browser/metrics/user_metrics.h"
14#include "chrome/browser/prefs/pref_service.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/ui/browser.h"
17#include "chrome/browser/ui/browser_list.h"
18#include "chrome/common/pref_names.h"
19#include "content/browser/tab_contents/page_navigator.h"
20#include "grit/generated_resources.h"
21#include "ui/base/l10n/l10n_util.h"
22
23BookmarkContextMenuController::BookmarkContextMenuController(
24    gfx::NativeWindow parent_window,
25    BookmarkContextMenuControllerDelegate* delegate,
26    Profile* profile,
27    PageNavigator* navigator,
28    const BookmarkNode* parent,
29    const std::vector<const BookmarkNode*>& selection)
30    : parent_window_(parent_window),
31      delegate_(delegate),
32      profile_(profile),
33      navigator_(navigator),
34      parent_(parent),
35      selection_(selection),
36      model_(profile->GetBookmarkModel()) {
37  DCHECK(profile_);
38  DCHECK(model_->IsLoaded());
39  menu_model_.reset(new ui::SimpleMenuModel(this));
40  model_->AddObserver(this);
41
42  BuildMenu();
43}
44
45BookmarkContextMenuController::~BookmarkContextMenuController() {
46  if (model_)
47    model_->RemoveObserver(this);
48}
49
50void BookmarkContextMenuController::BuildMenu() {
51  if (selection_.size() == 1 && selection_[0]->is_url()) {
52    AddItem(IDC_BOOKMARK_BAR_OPEN_ALL,
53            IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB);
54    AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
55            IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW);
56    AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
57            IDS_BOOMARK_BAR_OPEN_INCOGNITO);
58  } else {
59    AddItem(IDC_BOOKMARK_BAR_OPEN_ALL, IDS_BOOMARK_BAR_OPEN_ALL);
60    AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
61        IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW);
62    AddItem(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
63        IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO);
64  }
65
66  AddSeparator();
67  if (selection_.size() == 1 && selection_[0]->is_folder()) {
68    AddItem(IDC_BOOKMARK_BAR_RENAME_FOLDER, IDS_BOOKMARK_BAR_RENAME_FOLDER);
69  } else {
70    AddItem(IDC_BOOKMARK_BAR_EDIT, IDS_BOOKMARK_BAR_EDIT);
71  }
72
73  AddSeparator();
74  AddItem(IDC_CUT, IDS_CUT);
75  AddItem(IDC_COPY, IDS_COPY);
76  AddItem(IDC_PASTE, IDS_PASTE);
77
78  AddSeparator();
79  AddItem(IDC_BOOKMARK_BAR_REMOVE, IDS_BOOKMARK_BAR_REMOVE);
80
81  AddSeparator();
82  AddItem(IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK, IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK);
83  AddItem(IDC_BOOKMARK_BAR_NEW_FOLDER, IDS_BOOMARK_BAR_NEW_FOLDER);
84
85  AddSeparator();
86  AddItem(IDC_BOOKMARK_MANAGER, IDS_BOOKMARK_MANAGER);
87  AddCheckboxItem(IDC_BOOKMARK_BAR_ALWAYS_SHOW, IDS_BOOMARK_BAR_ALWAYS_SHOW);
88}
89
90void BookmarkContextMenuController::AddItem(int id, int localization_id) {
91  menu_model_->AddItemWithStringId(id, localization_id);
92}
93
94void BookmarkContextMenuController::AddSeparator() {
95  menu_model_->AddSeparator();
96}
97
98void BookmarkContextMenuController::AddCheckboxItem(int id,
99                                                    int localization_id) {
100  menu_model_->AddCheckItemWithStringId(id, localization_id);
101}
102
103void BookmarkContextMenuController::ExecuteCommand(int id) {
104  if (delegate_)
105    delegate_->WillExecuteCommand();
106
107  switch (id) {
108    case IDC_BOOKMARK_BAR_OPEN_ALL:
109    case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO:
110    case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW: {
111      WindowOpenDisposition initial_disposition;
112      if (id == IDC_BOOKMARK_BAR_OPEN_ALL) {
113        initial_disposition = NEW_FOREGROUND_TAB;
114        UserMetrics::RecordAction(
115            UserMetricsAction("BookmarkBar_ContextMenu_OpenAll"),
116            profile_);
117      } else if (id == IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW) {
118        initial_disposition = NEW_WINDOW;
119        UserMetrics::RecordAction(
120                UserMetricsAction("BookmarkBar_ContextMenu_OpenAllInNewWindow"),
121                profile_);
122      } else {
123        initial_disposition = OFF_THE_RECORD;
124        UserMetrics::RecordAction(
125            UserMetricsAction("BookmarkBar_ContextMenu_OpenAllIncognito"),
126            profile_);
127      }
128      bookmark_utils::OpenAll(parent_window_, profile_, navigator_, selection_,
129                              initial_disposition);
130      break;
131    }
132
133    case IDC_BOOKMARK_BAR_RENAME_FOLDER:
134    case IDC_BOOKMARK_BAR_EDIT:
135      UserMetrics::RecordAction(
136          UserMetricsAction("BookmarkBar_ContextMenu_Edit"),
137          profile_);
138
139      if (selection_.size() != 1) {
140        NOTREACHED();
141        break;
142      }
143
144      if (selection_[0]->is_url()) {
145        BookmarkEditor::Show(parent_window_, profile_, parent_,
146                             BookmarkEditor::EditDetails(selection_[0]),
147                             BookmarkEditor::SHOW_TREE);
148      } else {
149        BookmarkFolderEditorController::Show(profile_, parent_window_,
150            selection_[0], -1,
151            BookmarkFolderEditorController::EXISTING_BOOKMARK);
152      }
153      break;
154
155    case IDC_BOOKMARK_BAR_REMOVE: {
156      UserMetrics::RecordAction(
157          UserMetricsAction("BookmarkBar_ContextMenu_Remove"),
158          profile_);
159
160      for (size_t i = 0; i < selection_.size(); ++i) {
161        int index = selection_[i]->parent()->GetIndexOf(selection_[i]);
162        if (index > -1)
163          model_->Remove(selection_[i]->parent(), index);
164      }
165      selection_.clear();
166      break;
167    }
168
169    case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK: {
170      UserMetrics::RecordAction(
171          UserMetricsAction("BookmarkBar_ContextMenu_Add"),
172          profile_);
173
174      // TODO: this should honor the index from GetParentForNewNodes.
175      BookmarkEditor::Show(
176          parent_window_, profile_,
177          bookmark_utils::GetParentForNewNodes(parent_, selection_, NULL),
178          BookmarkEditor::EditDetails(), BookmarkEditor::SHOW_TREE);
179      break;
180    }
181
182    case IDC_BOOKMARK_BAR_NEW_FOLDER: {
183      UserMetrics::RecordAction(
184          UserMetricsAction("BookmarkBar_ContextMenu_NewFolder"),
185          profile_);
186      int index;
187      const BookmarkNode* parent =
188          bookmark_utils::GetParentForNewNodes(parent_, selection_, &index);
189      BookmarkFolderEditorController::Show(profile_, parent_window_, parent,
190          index, BookmarkFolderEditorController::NEW_BOOKMARK);
191      break;
192    }
193
194    case IDC_BOOKMARK_BAR_ALWAYS_SHOW:
195      bookmark_utils::ToggleWhenVisible(profile_);
196      break;
197
198    case IDC_BOOKMARK_MANAGER:
199      UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"),
200                                profile_);
201      {
202        Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
203        if (browser)
204          browser->OpenBookmarkManager();
205        else
206          NOTREACHED();
207      }
208      break;
209
210    case IDC_CUT:
211      bookmark_utils::CopyToClipboard(model_, selection_, true);
212      break;
213
214    case IDC_COPY:
215      bookmark_utils::CopyToClipboard(model_, selection_, false);
216      break;
217
218    case IDC_PASTE: {
219      int index;
220      const BookmarkNode* paste_target =
221          bookmark_utils::GetParentForNewNodes(parent_, selection_, &index);
222      if (!paste_target)
223        return;
224
225      bookmark_utils::PasteFromClipboard(model_, paste_target, index);
226      break;
227    }
228
229    default:
230      NOTREACHED();
231  }
232
233  if (delegate_)
234    delegate_->DidExecuteCommand();
235}
236
237bool BookmarkContextMenuController::IsCommandIdChecked(int command_id) const {
238  DCHECK(command_id == IDC_BOOKMARK_BAR_ALWAYS_SHOW);
239  return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
240}
241
242bool BookmarkContextMenuController::IsCommandIdEnabled(int command_id) const {
243  bool is_root_node =
244      (selection_.size() == 1 &&
245       selection_[0]->parent() == model_->root_node());
246  bool can_edit =
247      profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled);
248  switch (command_id) {
249    case IDC_BOOKMARK_BAR_OPEN_INCOGNITO:
250      return !profile_->IsOffTheRecord() &&
251             profile_->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled);
252
253    case IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO:
254      return HasURLs() && !profile_->IsOffTheRecord() &&
255             profile_->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled);
256
257    case IDC_BOOKMARK_BAR_OPEN_ALL:
258    case IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW:
259      return HasURLs();
260
261    case IDC_BOOKMARK_BAR_RENAME_FOLDER:
262    case IDC_BOOKMARK_BAR_EDIT:
263      return selection_.size() == 1 && !is_root_node && can_edit;
264
265    case IDC_BOOKMARK_BAR_REMOVE:
266      return !selection_.empty() && !is_root_node && can_edit;
267
268    case IDC_BOOKMARK_BAR_NEW_FOLDER:
269    case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK:
270      return can_edit && bookmark_utils::GetParentForNewNodes(
271          parent_, selection_, NULL) != NULL;
272
273    case IDC_BOOKMARK_BAR_ALWAYS_SHOW:
274      return !profile_->GetPrefs()->IsManagedPreference(
275          prefs::kEnableBookmarkBar);
276
277    case IDC_COPY:
278    case IDC_CUT:
279      return !selection_.empty() && !is_root_node &&
280             (command_id == IDC_COPY || can_edit);
281
282    case IDC_PASTE:
283      // Paste to selection from the Bookmark Bar, to parent_ everywhere else
284      return can_edit &&
285             ((!selection_.empty() &&
286               bookmark_utils::CanPasteFromClipboard(selection_[0])) ||
287              bookmark_utils::CanPasteFromClipboard(parent_));
288  }
289  return true;
290}
291
292bool BookmarkContextMenuController::GetAcceleratorForCommandId(
293    int command_id,
294    ui::Accelerator* accelerator) {
295  return false;
296}
297
298void BookmarkContextMenuController::BookmarkModelChanged() {
299  if (delegate_)
300    delegate_->CloseMenu();
301}
302
303bool BookmarkContextMenuController::HasURLs() const {
304  for (size_t i = 0; i < selection_.size(); ++i) {
305    if (bookmark_utils::NodeHasURLs(selection_[i]))
306      return true;
307  }
308  return false;
309}
310