summaryrefslogtreecommitdiffstats
path: root/chrome/browser/bookmarks
diff options
context:
space:
mode:
authorsky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-29 23:38:06 +0000
committersky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-29 23:38:06 +0000
commit7f856bee73ffdccdbbbbbab4cb79185290d38359 (patch)
treea837328e08a113abdc70b2fc0ae2f2a4a3f804eb /chrome/browser/bookmarks
parent281fe14063dd8fb81cea102f5abb7b82f407c3d1 (diff)
downloadchromium_src-7f856bee73ffdccdbbbbbab4cb79185290d38359.zip
chromium_src-7f856bee73ffdccdbbbbbab4cb79185290d38359.tar.gz
chromium_src-7f856bee73ffdccdbbbbbab4cb79185290d38359.tar.bz2
First cut at the bookmark manager. There are still a fair number of
rough edges, but I'm at a good point where I want to land what I have. Here's what is left: . Flicker on show, likely the result of restoring window placement. . tree flickers when dragging splitter. . table/tree need to autoscroll when drop cursor held at bottom of view. . prompts for deleting. . When you move an item the table snaps to the top, this is because I'm sending out model changed. need a better notification. . Operations in menu to add need to change selection. . Remember split location. I would have preferred to split this up into a couple of reviews, but everything is intertwined now. Sorry. BUG=674 TEST=don't test the bookmark manager yet, but make sure bookmark bar still works. Review URL: http://codereview.chromium.org/8197 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4191 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/bookmarks')
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu.cc458
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu.h105
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu_test.cc271
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_utils.cc91
-rw-r--r--chrome/browser/bookmarks/bookmark_folder_tree_model.cc2
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc241
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h (renamed from chrome/browser/bookmarks/bookmark_drag_utils.h)36
7 files changed, 1106 insertions, 98 deletions
diff --git a/chrome/browser/bookmarks/bookmark_context_menu.cc b/chrome/browser/bookmarks/bookmark_context_menu.cc
new file mode 100644
index 0000000..4f033ac
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_context_menu.cc
@@ -0,0 +1,458 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/bookmarks/bookmark_context_menu.h"
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/page_navigator.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents.h"
+#include "chrome/browser/user_metrics.h"
+#include "chrome/browser/views/bookmark_bar_view.h"
+#include "chrome/browser/views/bookmark_editor_view.h"
+#include "chrome/browser/views/bookmark_manager_view.h"
+#include "chrome/browser/views/input_window.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/views/container.h"
+#include "chrome/views/window.h"
+
+#include "generated_resources.h"
+
+namespace {
+
+// Returns true if the specified node is of type URL, or has a descendant
+// of type URL.
+bool NodeHasURLs(BookmarkNode* node) {
+ if (node->is_url())
+ return true;
+
+ for (int i = 0; i < node->GetChildCount(); ++i) {
+ if (NodeHasURLs(node->GetChild(i)))
+ return true;
+ }
+ return false;
+}
+
+// EditFolderController -------------------------------------------------------
+
+// EditFolderController manages the editing and/or creation of a folder. If the
+// user presses ok, the name change is committed to the model.
+//
+// EditFolderController deletes itself when the window is closed.
+class EditFolderController : public InputWindowDelegate,
+ public BookmarkModelObserver {
+ public:
+ virtual ~EditFolderController() {
+ if (model_)
+ model_->RemoveObserver(this);
+ }
+
+ static void Show(Profile* profile,
+ HWND hwnd,
+ BookmarkNode* node,
+ bool is_new) {
+ // EditFolderController deletes itself when done.
+ EditFolderController* controller =
+ new EditFolderController(profile, hwnd, node, is_new);
+ controller->Show();
+ }
+
+ private:
+ EditFolderController(Profile* profile,
+ HWND hwnd,
+ BookmarkNode* node,
+ bool is_new)
+ : profile_(profile),
+ model_(profile->GetBookmarkModel()),
+ node_(node),
+ is_new_(is_new) {
+ DCHECK(is_new_ || node);
+ window_ = CreateInputWindow(hwnd, this);
+ model_->AddObserver(this);
+ }
+
+ void Show() {
+ window_->Show();
+ }
+
+ // InputWindowDelegate methods.
+ virtual std::wstring GetTextFieldLabel() {
+ return l10n_util::GetString(IDS_BOOMARK_BAR_EDIT_FOLDER_LABEL);
+ }
+
+ virtual std::wstring GetTextFieldContents() {
+ if (is_new_)
+ return l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME);
+ return node_->GetTitle();
+ }
+
+ virtual bool IsValid(const std::wstring& text) {
+ return !text.empty();
+ }
+
+ virtual void InputAccepted(const std::wstring& text) {
+ if (is_new_)
+ model_->AddGroup(node_, node_->GetChildCount(), text);
+ else
+ model_->SetTitle(node_, text);
+ }
+
+ virtual void InputCanceled() {
+ }
+
+ virtual void WindowClosing() {
+ delete this;
+ }
+
+ virtual std::wstring GetWindowTitle() const {
+ return is_new_ ?
+ l10n_util::GetString(IDS_BOOMARK_FOLDER_EDITOR_WINDOW_TITLE_NEW) :
+ l10n_util::GetString(IDS_BOOMARK_FOLDER_EDITOR_WINDOW_TITLE);
+ }
+
+ // BookmarkModelObserver methods, all invoke ModelChanged and close the
+ // dialog.
+ virtual void Loaded(BookmarkModel* model) {}
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model) {
+ model_->RemoveObserver(this);
+ model_ = NULL;
+ ModelChanged();
+ }
+
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ BookmarkNode* old_parent,
+ int old_index,
+ BookmarkNode* new_parent,
+ int new_index) {
+ ModelChanged();
+ }
+
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index) {
+ ModelChanged();
+ }
+
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index,
+ BookmarkNode* node) {
+ ModelChanged();
+ }
+
+ virtual void BookmarkNodeChanged(BookmarkModel* model, BookmarkNode* node) {
+ ModelChanged();
+ }
+
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ BookmarkNode* node) {}
+
+ void ModelChanged() {
+ window_->Close();
+ }
+
+ Profile* profile_;
+ BookmarkModel* model_;
+ // If is_new is true, this is the parent to create the new node under.
+ // Otherwise this is the node to change the title of.
+ BookmarkNode* node_;
+
+ bool is_new_;
+ views::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(EditFolderController);
+};
+
+} // namespace
+
+// BookmarkContextMenu -------------------------------------------
+
+BookmarkContextMenu::BookmarkContextMenu(
+ HWND hwnd,
+ Profile* profile,
+ Browser* browser,
+ PageNavigator* navigator,
+ BookmarkNode* parent,
+ const std::vector<BookmarkNode*>& selection,
+ ConfigurationType configuration)
+ : hwnd_(hwnd),
+ profile_(profile),
+ browser_(browser),
+ navigator_(navigator),
+ parent_(parent),
+ selection_(selection),
+ model_(profile->GetBookmarkModel()),
+ configuration_(configuration) {
+ DCHECK(profile_);
+ DCHECK(model_->IsLoaded());
+ menu_.reset(new views::MenuItemView(this));
+ if (selection.size() == 1 && selection[0]->is_url()) {
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_OPEN_ALL,
+ l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_IN_NEW_TAB));
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_IN_NEW_WINDOW));
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO,
+ l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_INCOGNITO));
+ } else {
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_OPEN_ALL,
+ l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_ALL));
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW,
+ l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO,
+ l10n_util::GetString(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ }
+ menu_->AppendSeparator();
+
+ menu_->AppendMenuItemWithLabel(IDS_BOOKMARK_BAR_EDIT,
+ l10n_util::GetString(IDS_BOOKMARK_BAR_EDIT));
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOKMARK_BAR_REMOVE,
+ l10n_util::GetString(IDS_BOOKMARK_BAR_REMOVE));
+
+ if (configuration != BOOKMARK_BAR) {
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER,
+ l10n_util::GetString(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ }
+
+ menu_->AppendSeparator();
+
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK,
+ l10n_util::GetString(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ menu_->AppendMenuItemWithLabel(
+ IDS_BOOMARK_BAR_NEW_FOLDER,
+ l10n_util::GetString(IDS_BOOMARK_BAR_NEW_FOLDER));
+
+ if (configuration == BOOKMARK_BAR) {
+ menu_->AppendSeparator();
+ menu_->AppendMenuItemWithLabel(IDS_BOOKMARK_MANAGER,
+ l10n_util::GetString(IDS_BOOKMARK_MANAGER));
+ menu_->AppendMenuItem(IDS_BOOMARK_BAR_ALWAYS_SHOW,
+ l10n_util::GetString(IDS_BOOMARK_BAR_ALWAYS_SHOW),
+ views::MenuItemView::CHECKBOX);
+ }
+ model_->AddObserver(this);
+}
+
+BookmarkContextMenu::~BookmarkContextMenu() {
+ if (model_)
+ model_->RemoveObserver(this);
+}
+
+void BookmarkContextMenu::RunMenuAt(int x, int y) {
+ if (!model_->IsLoaded()) {
+ NOTREACHED();
+ return;
+ }
+ // width/height don't matter here.
+ menu_->RunMenuAt(hwnd_, gfx::Rect(x, y, 0, 0), views::MenuItemView::TOPLEFT,
+ true);
+}
+
+void BookmarkContextMenu::ExecuteCommand(int id) {
+ switch (id) {
+ case IDS_BOOMARK_BAR_OPEN_ALL:
+ case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
+ case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW: {
+ PageNavigator* navigator = browser_ ?
+ browser_->GetSelectedTabContents() : navigator_;
+ WindowOpenDisposition initial_disposition;
+ if (id == IDS_BOOMARK_BAR_OPEN_ALL) {
+ initial_disposition = NEW_FOREGROUND_TAB;
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_OpenAll",
+ profile_);
+ } else if (id == IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW) {
+ initial_disposition = NEW_WINDOW;
+ UserMetrics::RecordAction(
+ L"BookmarkBar_ContextMenu_OpenAllInNewWindow", profile_);
+ } else {
+ initial_disposition = OFF_THE_RECORD;
+ UserMetrics::RecordAction(
+ L"BookmarkBar_ContextMenu_OpenAllIncognito", profile_);
+ }
+
+ bookmark_utils::OpenAll(hwnd_, profile_, navigator, selection_,
+ initial_disposition);
+ break;
+ }
+
+ case IDS_BOOKMARK_BAR_EDIT:
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_Edit", profile_);
+
+ if (selection_.size() != 1) {
+ NOTREACHED();
+ return;
+ }
+
+ if (selection_[0]->is_url()) {
+ BookmarkEditorView::Configuration editor_config;
+ if (configuration_ == BOOKMARK_BAR)
+ editor_config = BookmarkEditorView::SHOW_TREE;
+ else
+ editor_config = BookmarkEditorView::NO_TREE;
+ BookmarkEditorView::Show(hwnd_, profile_, NULL, selection_[0],
+ editor_config);
+ } else {
+ EditFolderController::Show(profile_, hwnd_, selection_[0], false);
+ }
+ break;
+
+ case IDS_BOOKMARK_BAR_REMOVE: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_Remove", profile_);
+ BookmarkModel* model = RemoveModelObserver();
+
+ for (size_t i = 0; i < selection_.size(); ++i) {
+ model->Remove(selection_[i]->GetParent(),
+ selection_[i]->GetParent()->IndexOfChild(selection_[i]));
+ }
+ selection_.clear();
+ break;
+ }
+
+ case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_Add", profile_);
+
+ BookmarkEditorView::Configuration editor_config;
+ if (configuration_ == BOOKMARK_BAR)
+ editor_config = BookmarkEditorView::SHOW_TREE;
+ else
+ editor_config = BookmarkEditorView::NO_TREE;
+ BookmarkEditorView::Show(hwnd_, profile_, GetParentForNewNodes(), NULL,
+ editor_config);
+ break;
+ }
+
+ case IDS_BOOMARK_BAR_NEW_FOLDER: {
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_NewFolder",
+ profile_);
+
+ EditFolderController::Show(profile_, hwnd_, GetParentForNewNodes(),
+ true);
+ break;
+ }
+
+ case IDS_BOOMARK_BAR_ALWAYS_SHOW:
+ BookmarkBarView::ToggleWhenVisible(profile_);
+ break;
+
+ case IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER:
+ UserMetrics::RecordAction(L"BookmarkBar_ContextMenu_ShowInFolder",
+ profile_);
+
+ if (selection_.size() != 1) {
+ NOTREACHED();
+ return;
+ }
+
+ if (BookmarkManagerView::current())
+ BookmarkManagerView::current()->SelectInTree(selection_[0]);
+ break;
+
+ default:
+ NOTREACHED();
+ }
+}
+
+bool BookmarkContextMenu::IsItemChecked(int id) const {
+ DCHECK(id == IDS_BOOMARK_BAR_ALWAYS_SHOW);
+ return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar);
+}
+
+bool BookmarkContextMenu::IsCommandEnabled(int id) const {
+ bool is_root_node =
+ (selection_.size() == 1 &&
+ selection_[0]->GetParent() == model_->root_node());
+ switch (id) {
+ case IDS_BOOMARK_BAR_OPEN_INCOGNITO:
+ return !profile_->IsOffTheRecord();
+
+ case IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO:
+ return HasURLs() && !profile_->IsOffTheRecord();
+
+ case IDS_BOOMARK_BAR_OPEN_ALL:
+ case IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW:
+ return HasURLs();
+
+ case IDS_BOOKMARK_BAR_EDIT:
+ return selection_.size() == 1 && !is_root_node;
+
+ case IDS_BOOKMARK_BAR_REMOVE:
+ return !selection_.empty() && !is_root_node;
+
+ case IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER:
+ return configuration_ == BOOKMARK_MANAGER_TABLE &&
+ selection_.size() == 1;
+
+ case IDS_BOOMARK_BAR_NEW_FOLDER:
+ case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK:
+ return GetParentForNewNodes() != NULL;
+ }
+ return true;
+}
+
+void BookmarkContextMenu::BookmarkModelBeingDeleted(BookmarkModel* model) {
+ ModelChanged();
+}
+
+void BookmarkContextMenu::BookmarkNodeMoved(BookmarkModel* model,
+ BookmarkNode* old_parent,
+ int old_index,
+ BookmarkNode* new_parent,
+ int new_index) {
+ ModelChanged();
+}
+
+void BookmarkContextMenu::BookmarkNodeAdded(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index) {
+ ModelChanged();
+}
+
+void BookmarkContextMenu::BookmarkNodeRemoved(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index,
+ BookmarkNode* node) {
+ ModelChanged();
+}
+
+void BookmarkContextMenu::BookmarkNodeChanged(BookmarkModel* model,
+ BookmarkNode* node) {
+ ModelChanged();
+}
+
+void BookmarkContextMenu::ModelChanged() {
+ menu_->Cancel();
+}
+
+BookmarkModel* BookmarkContextMenu::RemoveModelObserver() {
+ BookmarkModel* model = model_;
+ model_->RemoveObserver(this);
+ model_ = NULL;
+ return model;
+}
+
+bool BookmarkContextMenu::HasURLs() const {
+ for (size_t i = 0; i < selection_.size(); ++i) {
+ if (NodeHasURLs(selection_[i]))
+ return true;
+ }
+ return false;
+}
+
+BookmarkNode* BookmarkContextMenu::GetParentForNewNodes() const {
+ return (selection_.size() == 1 && selection_[0]->is_folder()) ?
+ selection_[0] : parent_;
+}
diff --git a/chrome/browser/bookmarks/bookmark_context_menu.h b/chrome/browser/bookmarks/bookmark_context_menu.h
new file mode 100644
index 0000000..5b48627
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_context_menu.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_CONTEXT_MENU_H_
+#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_CONTEXT_MENU_H_
+
+#include <vector>
+
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/views/chrome_menu.h"
+
+class Browser;
+class PageNavigator;
+
+// BookmarkContextMenu manages the context menu shown for the
+// bookmark bar, items on the bookmark bar, submenus of the bookmark bar and
+// the bookmark manager.
+class BookmarkContextMenu : public views::MenuDelegate,
+ public BookmarkModelObserver {
+ public:
+ // Used to configure what the context menu shows.
+ enum ConfigurationType {
+ BOOKMARK_BAR,
+ BOOKMARK_MANAGER_TABLE,
+ BOOKMARK_MANAGER_TREE
+ };
+
+ // Creates the bookmark context menu.
+ // |profile| is used for opening urls as well as enabling 'open incognito'.
+ // |browser| is used to determine the PageNavigator and may be null.
+ // |navigator| is used if |browser| is null, and is provided for testing.
+ // |parent| is the parent for newly created nodes if |selection| is empty.
+ // |selection| is the nodes the context menu operates on and may be empty.
+ // |configuration| determines which items to show.
+ BookmarkContextMenu(HWND hwnd,
+ Profile* profile,
+ Browser* browser,
+ PageNavigator* navigator,
+ BookmarkNode* parent,
+ const std::vector<BookmarkNode*>& selection,
+ ConfigurationType configuration);
+ virtual ~BookmarkContextMenu();
+
+ // Shows the menu at the specified place.
+ void RunMenuAt(int x, int y);
+
+ // Returns the menu.
+ views::MenuItemView* menu() const { return menu_.get(); }
+
+ // Menu::Delegate methods.
+ virtual void ExecuteCommand(int id);
+ virtual bool IsItemChecked(int id) const;
+ virtual bool IsCommandEnabled(int id) const;
+
+ private:
+ // BookmarkModelObserver method. Any change to the model results in closing
+ // the menu.
+ virtual void Loaded(BookmarkModel* model) {}
+ virtual void BookmarkModelBeingDeleted(BookmarkModel* model);
+ virtual void BookmarkNodeMoved(BookmarkModel* model,
+ BookmarkNode* old_parent,
+ int old_index,
+ BookmarkNode* new_parent,
+ int new_index);
+ virtual void BookmarkNodeAdded(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index);
+ virtual void BookmarkNodeRemoved(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index,
+ BookmarkNode* node);
+ virtual void BookmarkNodeChanged(BookmarkModel* model,
+ BookmarkNode* node);
+ virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
+ BookmarkNode* node) {}
+
+ // Invoked from the various bookmark model observer methods. Closes the menu.
+ void ModelChanged();
+
+ // Removes the observer from the model and NULLs out model_.
+ BookmarkModel* RemoveModelObserver();
+
+ // Returns true if selection_ has at least one bookmark of type url.
+ bool HasURLs() const;
+
+ // Returns the parent for newly created folders/bookmarks. If selection_
+ // has one element and it is a folder, selection_[0] is returned, otherwise
+ // parent_ is returned.
+ BookmarkNode* GetParentForNewNodes() const;
+
+ HWND hwnd_;
+ Profile* profile_;
+ Browser* browser_;
+ PageNavigator* navigator_;
+ BookmarkNode* parent_;
+ std::vector<BookmarkNode*> selection_;
+ scoped_ptr<views::MenuItemView> menu_;
+ BookmarkModel* model_;
+ ConfigurationType configuration_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkContextMenu);
+};
+
+#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_CONTEXT_MENU_H_
diff --git a/chrome/browser/bookmarks/bookmark_context_menu_test.cc b/chrome/browser/bookmarks/bookmark_context_menu_test.cc
new file mode 100644
index 0000000..e665058
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_context_menu_test.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/bookmarks/bookmark_context_menu.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/views/bookmark_bar_view.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/browser/page_navigator.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "generated_resources.h"
+
+namespace {
+
+// PageNavigator implementation that records the URL.
+class TestingPageNavigator : public PageNavigator {
+ public:
+ virtual void OpenURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
+ urls_.push_back(url);
+ }
+
+ std::vector<GURL> urls_;
+};
+
+} // namespace
+
+class BookmarkContextMenuTest : public testing::Test {
+ public:
+ BookmarkContextMenuTest()
+ : model_(NULL) {
+ }
+
+ virtual void SetUp() {
+ BookmarkBarView::testing_ = true;
+
+ profile_.reset(new TestingProfile());
+ profile_->set_has_history_service(true);
+ profile_->CreateBookmarkModel(true);
+ profile_->BlockUntilBookmarkModelLoaded();
+
+ model_ = profile_->GetBookmarkModel();
+
+ AddTestData();
+ }
+
+ virtual void TearDown() {
+ BookmarkBarView::testing_ = false;
+
+ // Flush the message loop to make Purify happy.
+ message_loop_.RunAllPending();
+ }
+
+ protected:
+ MessageLoopForUI message_loop_;
+ scoped_ptr<TestingProfile> profile_;
+ BookmarkModel* model_;
+ TestingPageNavigator navigator_;
+
+ private:
+ // Creates the following structure:
+ // a
+ // F1
+ // f1a
+ // F11
+ // f11a
+ // F2
+ // F3
+ // F4
+ // f4a
+ void AddTestData() {
+ std::string test_base = "file:///c:/tmp/";
+
+ model_->AddURL(model_->GetBookmarkBarNode(), 0, L"a",
+ GURL(test_base + "a"));
+ BookmarkNode* f1 =
+ model_->AddGroup(model_->GetBookmarkBarNode(), 1, L"F1");
+ model_->AddURL(f1, 0, L"f1a", GURL(test_base + "f1a"));
+ BookmarkNode* f11 = model_->AddGroup(f1, 1, L"F11");
+ model_->AddURL(f11, 0, L"f11a", GURL(test_base + "f11a"));
+ model_->AddGroup(model_->GetBookmarkBarNode(), 2, L"F2");
+ model_->AddGroup(model_->GetBookmarkBarNode(), 3, L"F3");
+ BookmarkNode* f4 =
+ model_->AddGroup(model_->GetBookmarkBarNode(), 4, L"F4");
+ model_->AddURL(f4, 0, L"f4a", GURL(test_base + "f4a"));
+ }
+};
+
+// Tests Deleting from the menu.
+TEST_F(BookmarkContextMenuTest, DeleteURL) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(), nodes,
+ BookmarkContextMenu::BOOKMARK_BAR);
+ GURL url = model_->GetBookmarkBarNode()->GetChild(0)->GetURL();
+ ASSERT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ // Delete the URL.
+ controller.ExecuteCommand(IDS_BOOKMARK_BAR_REMOVE);
+ // Model shouldn't have URL anymore.
+ ASSERT_FALSE(model_->IsBookmarked(url));
+}
+
+// Tests open all on a folder with a couple of bookmarks.
+TEST_F(BookmarkContextMenuTest, OpenAll) {
+ BookmarkNode* folder = model_->GetBookmarkBarNode()->GetChild(1);
+ bookmark_utils::OpenAll(
+ NULL, profile_.get(), &navigator_, folder, NEW_FOREGROUND_TAB);
+
+ // Should have navigated to F1's children.
+ ASSERT_EQ(2, navigator_.urls_.size());
+ ASSERT_TRUE(folder->GetChild(0)->GetURL() == navigator_.urls_[0]);
+ ASSERT_TRUE(folder->GetChild(1)->GetChild(0)->GetURL() ==
+ navigator_.urls_[1]);
+}
+
+// Tests the enabled state of the menus when supplied an empty vector.
+TEST_F(BookmarkContextMenuTest, EmptyNodes) {
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, model_->other_node(),
+ std::vector<BookmarkNode*>(), BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+}
+
+// Tests the enabled state of the menus when supplied a vector with a single
+// url.
+TEST_F(BookmarkContextMenuTest, SingleURL) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(),
+ nodes, BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+}
+
+// Tests the enabled state of the menus when supplied a vector with multiple
+// urls.
+TEST_F(BookmarkContextMenuTest, MultipleURLs) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(1)->GetChild(0));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(),
+ nodes, BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+}
+
+// Tests the enabled state of the menus when supplied an vector with a single
+// folder.
+TEST_F(BookmarkContextMenuTest, SingleFolder) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(2));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(),
+ nodes, BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+}
+
+// Tests the enabled state of the menus when supplied a vector with multiple
+// folders, all of which are empty.
+TEST_F(BookmarkContextMenuTest, MultipleEmptyFolders) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(2));
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(3));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(),
+ nodes, BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+}
+
+// Tests the enabled state of the menus when supplied a vector with multiple
+// folders, some of which contain URLs.
+TEST_F(BookmarkContextMenuTest, MultipleFoldersWithURLs) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(3));
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(4));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(),
+ nodes, BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+ EXPECT_TRUE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+ EXPECT_FALSE(
+ controller.IsCommandEnabled(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK));
+ EXPECT_TRUE(
+ controller.IsCommandEnabled(IDS_BOOMARK_BAR_NEW_FOLDER));
+}
+
+// Tests the enabled state of open incognito.
+TEST_F(BookmarkContextMenuTest, DisableIncognito) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->GetBookmarkBarNode()->GetChild(0));
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0]->GetParent(),
+ nodes, BookmarkContextMenu::BOOKMARK_BAR);
+ profile_->set_off_the_record(true);
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_INCOGNITO));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO));
+}
+
+// Tests that you can't remove/edit when showing the other node.
+TEST_F(BookmarkContextMenuTest, DisabledItemsWithOtherNode) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(model_->other_node());
+ BookmarkContextMenu controller(
+ NULL, profile_.get(), NULL, NULL, nodes[0], nodes,
+ BookmarkContextMenu::BOOKMARK_BAR);
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_EDIT));
+ EXPECT_FALSE(controller.IsCommandEnabled(IDS_BOOKMARK_BAR_REMOVE));
+}
diff --git a/chrome/browser/bookmarks/bookmark_drag_utils.cc b/chrome/browser/bookmarks/bookmark_drag_utils.cc
deleted file mode 100644
index 863369c..0000000
--- a/chrome/browser/bookmarks/bookmark_drag_utils.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/bookmarks/bookmark_drag_utils.h"
-
-#include "chrome/browser/bookmarks/bookmark_drag_data.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/common/drag_drop_types.h"
-#include "chrome/views/event.h"
-
-namespace {
-
-void CloneDragDataImpl(BookmarkModel* model,
- const BookmarkDragData::Element& element,
- BookmarkNode* parent,
- int index_to_add_at) {
- if (element.is_url) {
- model->AddURL(parent, index_to_add_at, element.title, element.url);
- } else {
- BookmarkNode* new_folder = model->AddGroup(parent, index_to_add_at,
- element.title);
- for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
- CloneDragDataImpl(model, element.children[i], new_folder, i);
- }
-}
-
-} // namespace
-
-namespace bookmark_drag_utils {
-
-int PreferredDropOperation(const views::DropTargetEvent& event,
- int operation) {
- int common_ops = (event.GetSourceOperations() & operation);
- if (!common_ops)
- return 0;
- if (DragDropTypes::DRAG_COPY & common_ops)
- return DragDropTypes::DRAG_COPY;
- if (DragDropTypes::DRAG_LINK & common_ops)
- return DragDropTypes::DRAG_LINK;
- if (DragDropTypes::DRAG_MOVE & common_ops)
- return DragDropTypes::DRAG_MOVE;
- return DragDropTypes::DRAG_NONE;
-}
-
-bool IsValidDropLocation(Profile* profile,
- const BookmarkDragData& data,
- BookmarkNode* drop_parent,
- int index) {
- if (!drop_parent->is_folder()) {
- NOTREACHED();
- return false;
- }
-
- if (!data.is_valid())
- return false;
-
- if (data.IsFromProfile(profile)) {
- std::vector<BookmarkNode*> nodes = data.GetNodes(profile);
- for (size_t i = 0; i < nodes.size(); ++i) {
- // Don't allow the drop if the user is attempting to drop on one of the
- // nodes being dragged.
- BookmarkNode* node = nodes[i];
- int node_index = (drop_parent == node->GetParent()) ?
- drop_parent->IndexOfChild(nodes[i]) : -1;
- if (node_index != -1 && (index == node_index || index == node_index + 1))
- return false;
-
- // drop_parent can't accept a child that is an ancestor.
- if (drop_parent->HasAncestor(node))
- return false;
- }
- return true;
- }
- // From the same profile, always accept.
- return true;
-}
-
-void CloneDragData(BookmarkModel* model,
- const std::vector<BookmarkDragData::Element>& elements,
- BookmarkNode* parent,
- int index_to_add_at) {
- if (!parent->is_folder() || !model) {
- NOTREACHED();
- return;
- }
- for (size_t i = 0; i < elements.size(); ++i)
- CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
-}
-
-} // namespace bookmark_drag_utils
diff --git a/chrome/browser/bookmarks/bookmark_folder_tree_model.cc b/chrome/browser/bookmarks/bookmark_folder_tree_model.cc
index f365e76..b1932a4 100644
--- a/chrome/browser/bookmarks/bookmark_folder_tree_model.cc
+++ b/chrome/browser/bookmarks/bookmark_folder_tree_model.cc
@@ -33,6 +33,8 @@ BookmarkFolderTreeModel::NodeType BookmarkFolderTreeModel::GetNodeType(
return RECENTLY_BOOKMARKED;
if (node == search_node_)
return SEARCH;
+ if (node == GetRoot())
+ return NONE;
return BOOKMARK;
}
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
new file mode 100644
index 0000000..d9b0be1
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/bookmarks/bookmark_utils.h"
+
+#include "chrome/browser/bookmarks/bookmark_drag_data.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/page_navigator.h"
+#include "chrome/browser/tab_contents.h"
+#include "chrome/common/drag_drop_types.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/views/event.h"
+
+#include "chromium_strings.h"
+#include "generated_resources.h"
+
+namespace {
+
+// Number of bookmarks we'll open before prompting the user to see if they
+// really want to open all.
+const int kNumURLsBeforePrompting = 15;
+
+// A PageNavigator implementation that creates a new Browser. This is used when
+// opening a url and there is no Browser open. The Browser is created the first
+// time the PageNavigator method is invoked.
+class NewBrowserPageNavigator : public PageNavigator {
+ public:
+ explicit NewBrowserPageNavigator(Profile* profile)
+ : profile_(profile),
+ browser_(NULL) {}
+
+ virtual ~NewBrowserPageNavigator() {
+ if (browser_)
+ browser_->Show();
+ }
+
+ Browser* browser() const { return browser_; }
+
+ virtual void OpenURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition) {
+ if (!browser_) {
+ Profile* profile = (disposition == OFF_THE_RECORD) ?
+ profile_->GetOffTheRecordProfile() : profile_;
+ browser_ = new Browser(gfx::Rect(), SW_SHOW, profile,
+ BrowserType::TABBED_BROWSER, std::wstring());
+ // Always open the first tab in the foreground.
+ disposition = NEW_FOREGROUND_TAB;
+ }
+ browser_->OpenURLFromTab(NULL, url, referrer, NEW_FOREGROUND_TAB, transition);
+ }
+
+ private:
+ Profile* profile_;
+ Browser* browser_;
+
+ DISALLOW_COPY_AND_ASSIGN(NewBrowserPageNavigator);
+};
+
+void CloneDragDataImpl(BookmarkModel* model,
+ const BookmarkDragData::Element& element,
+ BookmarkNode* parent,
+ int index_to_add_at) {
+ if (element.is_url) {
+ model->AddURL(parent, index_to_add_at, element.title, element.url);
+ } else {
+ BookmarkNode* new_folder = model->AddGroup(parent, index_to_add_at,
+ element.title);
+ for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
+ CloneDragDataImpl(model, element.children[i], new_folder, i);
+ }
+}
+
+// Returns the number of descendants of node that are of type url.
+int DescendantURLCount(BookmarkNode* node) {
+ int result = 0;
+ for (int i = 0; i < node->GetChildCount(); ++i) {
+ BookmarkNode* child = node->GetChild(i);
+ if (child->is_url())
+ result++;
+ else
+ result += DescendantURLCount(child);
+ }
+ return result;
+}
+
+// Implementation of OpenAll. Opens all nodes of type URL and recurses for
+// groups. |navigator| is the PageNavigator used to open URLs. After the first
+// url is opened |opened_url| is set to true and |navigator| is set to the
+// PageNavigator of the last active tab. This is done to handle a window
+// disposition of new window, in which case we want subsequent tabs to open in
+// that window.
+void OpenAllImpl(BookmarkNode* node,
+ WindowOpenDisposition initial_disposition,
+ PageNavigator** navigator,
+ bool* opened_url) {
+ if (node->is_url()) {
+ WindowOpenDisposition disposition;
+ if (*opened_url)
+ disposition = NEW_BACKGROUND_TAB;
+ else
+ disposition = initial_disposition;
+ (*navigator)->OpenURL(node->GetURL(), GURL(), disposition,
+ PageTransition::AUTO_BOOKMARK);
+ if (!*opened_url) {
+ *opened_url = true;
+ // We opened the first URL which may have opened a new window or clobbered
+ // the current page, reset the navigator just to be sure.
+ Browser* new_browser = BrowserList::GetLastActive();
+ if (new_browser) {
+ TabContents* current_tab = new_browser->GetSelectedTabContents();
+ DCHECK(new_browser && current_tab);
+ if (new_browser && current_tab)
+ *navigator = current_tab;
+ } // else, new_browser == NULL, which happens during testing.
+ }
+ } else {
+ // Group, recurse through children.
+ for (int i = 0; i < node->GetChildCount(); ++i) {
+ OpenAllImpl(node->GetChild(i), initial_disposition, navigator,
+ opened_url);
+ }
+ }
+}
+
+bool ShouldOpenAll(HWND parent, const std::vector<BookmarkNode*>& nodes) {
+ int descendant_count = 0;
+ for (size_t i = 0; i < nodes.size(); ++i)
+ descendant_count += DescendantURLCount(nodes[i]);
+ if (descendant_count < kNumURLsBeforePrompting)
+ return true;
+
+ std::wstring message =
+ l10n_util::GetStringF(IDS_BOOKMARK_BAR_SHOULD_OPEN_ALL,
+ IntToWString(descendant_count));
+ return MessageBox(parent, message.c_str(),
+ l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
+ MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDYES;
+}
+
+} // namespace
+
+namespace bookmark_utils {
+
+int PreferredDropOperation(const views::DropTargetEvent& event,
+ int operation) {
+ int common_ops = (event.GetSourceOperations() & operation);
+ if (!common_ops)
+ return 0;
+ if (DragDropTypes::DRAG_COPY & common_ops)
+ return DragDropTypes::DRAG_COPY;
+ if (DragDropTypes::DRAG_LINK & common_ops)
+ return DragDropTypes::DRAG_LINK;
+ if (DragDropTypes::DRAG_MOVE & common_ops)
+ return DragDropTypes::DRAG_MOVE;
+ return DragDropTypes::DRAG_NONE;
+}
+
+bool IsValidDropLocation(Profile* profile,
+ const BookmarkDragData& data,
+ BookmarkNode* drop_parent,
+ int index) {
+ if (!drop_parent->is_folder()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!data.is_valid())
+ return false;
+
+ if (data.IsFromProfile(profile)) {
+ std::vector<BookmarkNode*> nodes = data.GetNodes(profile);
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ // Don't allow the drop if the user is attempting to drop on one of the
+ // nodes being dragged.
+ BookmarkNode* node = nodes[i];
+ int node_index = (drop_parent == node->GetParent()) ?
+ drop_parent->IndexOfChild(nodes[i]) : -1;
+ if (node_index != -1 && (index == node_index || index == node_index + 1))
+ return false;
+
+ // drop_parent can't accept a child that is an ancestor.
+ if (drop_parent->HasAncestor(node))
+ return false;
+ }
+ return true;
+ }
+ // From the same profile, always accept.
+ return true;
+}
+
+void CloneDragData(BookmarkModel* model,
+ const std::vector<BookmarkDragData::Element>& elements,
+ BookmarkNode* parent,
+ int index_to_add_at) {
+ if (!parent->is_folder() || !model) {
+ NOTREACHED();
+ return;
+ }
+ for (size_t i = 0; i < elements.size(); ++i)
+ CloneDragDataImpl(model, elements[i], parent, index_to_add_at + i);
+}
+
+void OpenAll(HWND parent,
+ Profile* profile,
+ PageNavigator* navigator,
+ const std::vector<BookmarkNode*>& nodes,
+ WindowOpenDisposition initial_disposition) {
+ if (!ShouldOpenAll(parent, nodes))
+ return;
+
+ NewBrowserPageNavigator navigator_impl(profile);
+ if (!navigator) {
+ Browser* browser =
+ BrowserList::FindBrowserWithType(profile, BrowserType::TABBED_BROWSER);
+ if (!browser || !browser->GetSelectedTabContents())
+ navigator = &navigator_impl;
+ else
+ navigator = browser->GetSelectedTabContents();
+ }
+
+ bool opened_url = false;
+ for (size_t i = 0; i < nodes.size(); ++i)
+ OpenAllImpl(nodes[i], initial_disposition, &navigator, &opened_url);
+}
+
+void OpenAll(HWND parent,
+ Profile* profile,
+ PageNavigator* navigator,
+ BookmarkNode* node,
+ WindowOpenDisposition initial_disposition) {
+ std::vector<BookmarkNode*> nodes;
+ nodes.push_back(node);
+ OpenAll(parent, profile, navigator, nodes, initial_disposition);
+}
+
+} // namespace bookmark_utils
diff --git a/chrome/browser/bookmarks/bookmark_drag_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 2805311..0711638 100644
--- a/chrome/browser/bookmarks/bookmark_drag_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -2,21 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_UTILS_H_
-#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_UTILS_H_
+#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_
+#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_
+
+#include <vector>
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
+#include "webkit/glue/window_open_disposition.h"
class BookmarkNode;
+class PageNavigator;
class Profile;
namespace views {
class DropTargetEvent;
}
-// Functions used in managing bookmark drag and drop. These functions are
-// used by both the bookmark bar and bookmark manager.
-namespace bookmark_drag_utils {
+// A collection of bookmark utility functions used by various parts of the UI
+// that show bookmarks: bookmark manager, bookmark bar view ...
+namespace bookmark_utils {
// Calculates the drop operation given the event and supported set of
// operations. This prefers the following ordering: COPY, LINK then MOVE.
@@ -40,6 +44,24 @@ void CloneDragData(BookmarkModel* model,
BookmarkNode* parent,
int index_to_add_at);
-}
+// Recursively opens all bookmarks. |initial_disposition| dictates how the
+// first URL is opened, all subsequent URLs are opened as background tabs.
+// |navigator| is used to open the URLs. If |navigator| is NULL the last
+// tabbed browser with the profile |profile| is used. If there is no browser
+// with the specified profile a new one is created.
+void OpenAll(HWND parent,
+ Profile* profile,
+ PageNavigator* navigator,
+ const std::vector<BookmarkNode*>& nodes,
+ WindowOpenDisposition initial_disposition);
+
+// Convenience for opening a single BookmarkNode.
+void OpenAll(HWND parent,
+ Profile* profile,
+ PageNavigator* navigator,
+ BookmarkNode* node,
+ WindowOpenDisposition initial_disposition);
+
+} // namespace bookmark_utils
-#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_UTILS_H_
+#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_