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