summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-08 20:56:54 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-08 20:56:54 +0000
commitb3ac5c830a92eecabb94160169e72415d59a5509 (patch)
tree516d1fe562c060b0a6a04a2796c3909b2646b601
parent378c3fdf56d3f6328632f0e994a678c9387c78d3 (diff)
downloadchromium_src-b3ac5c830a92eecabb94160169e72415d59a5509.zip
chromium_src-b3ac5c830a92eecabb94160169e72415d59a5509.tar.gz
chromium_src-b3ac5c830a92eecabb94160169e72415d59a5509.tar.bz2
Adds the ability to create a bookmark folder populated with a bookmark
for each open tab. I've currently wired this up on windows, will wire up rest of platforms in a separate cl. BUG=2935 TEST=on Windows open multiple tabs, right click on a tab and choose 'Bookmark all tabs'. You should then get the bookmark editor with no url field. Accepting the dialog should result in creating a new folder with a bookmark for each of the open tabs. Review URL: http://codereview.chromium.org/270021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28446 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/bookmarks/bookmark_editor.h11
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc37
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h13
-rw-r--r--chrome/browser/browser.cc22
-rw-r--r--chrome/browser/browser.h1
-rw-r--r--chrome/browser/cocoa/tab_strip_controller_unittest.mm4
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc14
-rw-r--r--chrome/browser/tabs/tab_strip_model.h4
-rw-r--r--chrome/browser/tabs/tab_strip_model_unittest.cc1
-rw-r--r--chrome/browser/views/bookmark_editor_view.cc30
-rw-r--r--chrome/browser/views/bookmark_editor_view.h60
-rw-r--r--chrome/browser/views/bookmark_editor_view_unittest.cc174
-rw-r--r--chrome/browser/views/tabs/tab.cc10
14 files changed, 290 insertions, 97 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 015f683..528d447 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3279,6 +3279,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_TAB_CXMENU_PIN_TAB" desc="The label of the tab context menu item for pinning a tab.">
Pin tab
</message>
+ <message name="IDS_TAB_CXMENU_BOOKMARK_ALL_TABS" desc="In Title Case: The label of the tab context menu item for creating a bookmark folder containing an entry for each open tab.">
+ Bookmark all tabs...
+ </message>
</if>
<if expr="pp_ifdef('use_titlecase')">
<message name="IDS_TAB_CXMENU_NEWTAB" desc="In Title Case: The label of the 'New Tab' Tab context menu item.">
@@ -3305,6 +3308,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_TAB_CXMENU_PIN_TAB" desc="In Title Case: The label of the tab context menu item for pinning a tab.">
Pin Tab
</message>
+ <message name="IDS_TAB_CXMENU_BOOKMARK_ALL_TABS" desc="In Title Case: The label of the tab context menu item for creating a bookmark folder containing an entry for each open tab.">
+ Bookmark All Tabs...
+ </message>
</if>
<!-- Items in the bookmarks destination mode -->
diff --git a/chrome/browser/bookmarks/bookmark_editor.h b/chrome/browser/bookmarks/bookmark_editor.h
index b7dc15b..982c314 100644
--- a/chrome/browser/bookmarks/bookmark_editor.h
+++ b/chrome/browser/bookmarks/bookmark_editor.h
@@ -28,9 +28,14 @@ class BookmarkEditor {
NO_TREE
};
- // Shows the platform specific BookmarkEditor subclass editing |node|. If
- // |node| is NULL a new entry is created initially parented to |parent|. If
- // |show_tree| is false the tree is not shown. BookmarkEditor takes
+ // Shows the platform specific BookmarkEditor subclass editing |node|. |node|
+ // may be one of three values:
+ // . NULL, in which a case a new entry is created initially parented to
+ // |parent|.
+ // . non-null and a url.
+ // . non-null and a folder. In this case the url field is not shown and an
+ // entry for the node is not shown in the tree.
+ // If |show_tree| is false the tree is not shown. BookmarkEditor takes
// ownership of |handler| and deletes it when done. |handler| may be
// null. See description of Handler for details.
static void Show(gfx::NativeView parent_window,
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index 945e22a..95cfe64 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -549,14 +549,14 @@ const BookmarkNode* ApplyEditsWithPossibleGroupChange(BookmarkModel* model,
Time date_added = node->date_added();
if (new_parent == node->GetParent()) {
// The parent is the same.
- if (new_url != node->GetURL()) {
+ if (node->is_url() && new_url != node->GetURL()) {
model->Remove(old_parent, old_index);
return_node = model->AddURLWithCreationTime(old_parent, old_index,
new_title, new_url, date_added);
} else {
model->SetTitle(node, new_title);
}
- } else if (new_url != node->GetURL()) {
+ } else if (node->is_url() && new_url != node->GetURL()) {
// The parent and URL changed.
model->Remove(old_parent, old_index);
return_node = model->AddURLWithCreationTime(new_parent,
@@ -594,13 +594,11 @@ void ToggleWhenVisible(Profile* profile) {
NotificationService::NoDetails());
}
-// static
void RegisterPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kBookmarkManagerPlacement);
prefs->RegisterIntegerPref(prefs::kBookmarkManagerSplitLocation, -1);
}
-// static
void RegisterUserPrefs(PrefService* prefs) {
// Formerly in BookmarkBarView
prefs->RegisterBooleanPref(prefs::kShowBookmarkBar, false);
@@ -613,4 +611,35 @@ void RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kBookmarkTablePathWidth, -1);
}
+bool GetURLAndTitleToBookmark(TabContents* tab_contents,
+ GURL* url,
+ std::wstring* title) {
+ if (!tab_contents->ShouldDisplayURL())
+ return false;
+ *url = tab_contents->GetURL();
+ if (url->is_empty() || !url->is_valid())
+ return false;
+ *title = UTF16ToWideHack(tab_contents->GetTitle());
+ return true;
+}
+
+const BookmarkNode* CreateBookmarkForAllTabs(Browser* browser) {
+ BookmarkModel* model = browser->profile()->GetBookmarkModel();
+ if (!model || !model->IsLoaded())
+ return NULL;
+
+ const BookmarkNode* parent = model->GetParentForNewNodes();
+ const BookmarkNode* folder = model->AddGroup(
+ parent, parent->GetChildCount(),
+ l10n_util::GetString(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME));
+ for (int i = 0; i < browser->tab_count(); ++i) {
+ GURL url;
+ std::wstring title;
+ if (GetURLAndTitleToBookmark(browser->GetTabContentsAt(i), &url, &title)) {
+ model->AddURL(folder, folder->GetChildCount(), title, url);
+ }
+ }
+ return folder;
+}
+
} // namespace bookmark_utils
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 0c4ecab..d45ecad 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -16,9 +16,11 @@
class BookmarkModel;
class BookmarkNode;
+class Browser;
class PageNavigator;
class PrefService;
class Profile;
+class TabContents;
namespace views {
class DropTargetEvent;
@@ -180,6 +182,17 @@ void RegisterPrefs(PrefService* prefs);
// Register user prefs for BookmarkBar, BookmarkView, ...
void RegisterUserPrefs(PrefService* prefs);
+// Gets the url and title to use in creating a bookmark for the specified
+// TabContents. Returns false if a bookmark shouldn't be created for the
+// specified TabContents.
+bool GetURLAndTitleToBookmark(TabContents* tab_contents,
+ GURL* url,
+ std::wstring* title);
+
+// Creates a new folder containing a bookmark for each of the tabs in
+// |browser|. This returns null if the bookmark model isn't loaded.
+const BookmarkNode* CreateBookmarkForAllTabs(Browser* browser);
+
// Number of bookmarks we'll open before prompting the user to see if they
// really want to open all.
//
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 0aa1e2b..27ad096 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -13,6 +13,7 @@
#include "base/thread.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
@@ -897,12 +898,10 @@ void Browser::BookmarkCurrentPage() {
UserMetrics::RecordAction(L"Star", profile_);
TabContents* contents = GetSelectedTabContents();
- if (!contents->ShouldDisplayURL())
- return;
- const GURL& url = contents->GetURL();
- if (url.is_empty() || !url.is_valid())
+ GURL url;
+ std::wstring title;
+ if (!bookmark_utils::GetURLAndTitleToBookmark(contents, &url, &title))
return;
- std::wstring title = UTF16ToWideHack(contents->GetTitle());
BookmarkModel* model = contents->profile()->GetBookmarkModel();
if (!model || !model->IsLoaded())
@@ -1680,6 +1679,19 @@ bool Browser::CanCloseContentsAt(int index) {
return CanCloseWithInProgressDownloads();
}
+void Browser::BookmarkAllTabs() {
+ const BookmarkNode* node = bookmark_utils::CreateBookmarkForAllTabs(this);
+ if (!node)
+ return;
+
+ // TODO(sky): BookmarkEditor::Show should take a NativeWindow, not view.
+#if defined(OS_WIN)
+ BookmarkEditor::Show(window()->GetNativeHandle(), profile_,
+ node->GetParent(), node, BookmarkEditor::SHOW_TREE,
+ NULL);
+#endif
+}
+
///////////////////////////////////////////////////////////////////////////////
// Browser, TabStripModelObserver implementation:
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 646f559..d176b1d 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -474,6 +474,7 @@ class Browser : public TabStripModelDelegate,
virtual void CreateHistoricalTab(TabContents* contents);
virtual bool RunUnloadListenerBeforeClosing(TabContents* contents);
virtual bool CanCloseContentsAt(int index);
+ virtual void BookmarkAllTabs();
// Overridden from TabStripModelObserver:
virtual void TabInsertedAt(TabContents* contents,
diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
index 9d71eb3..bcc2cf8 100644
--- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm
+++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
@@ -53,9 +53,11 @@ class TestTabStripDelegate : public TabStripModelDelegate {
virtual bool CanRestoreTab() {
return true;
}
- virtual void RestoreTab() { }
+ virtual void RestoreTab() {}
virtual bool CanCloseContentsAt(int index) { return true; }
+
+ virtual void BookmarkAllTabs() {}
};
class TabStripControllerTest : public PlatformTest {
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index b356c62..9ceb6d8 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -10,6 +10,7 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "build/build_config.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
@@ -486,6 +487,12 @@ bool TabStripModel::IsContextMenuCommandEnabled(
return delegate_->CanRestoreTab();
case CommandTogglePinned:
return true;
+ case CommandBookmarkAllTabs: {
+ if (count() <= 1)
+ return false;
+ BookmarkModel* model = profile_->GetBookmarkModel();
+ return model && model->IsLoaded();
+ }
default:
NOTREACHED();
}
@@ -550,6 +557,13 @@ void TabStripModel::ExecuteContextMenuCommand(
SetTabPinned(context_index, !IsTabPinned(context_index));
break;
}
+
+ case CommandBookmarkAllTabs: {
+ UserMetrics::RecordAction(L"TabContextMenu_BookmarkAllTabs", profile_);
+
+ delegate_->BookmarkAllTabs();
+ break;
+ }
default:
NOTREACHED();
}
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index cbf23a7..9e7659e 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -199,6 +199,9 @@ class TabStripModelDelegate {
// Returns whether some contents can be closed.
virtual bool CanCloseContentsAt(int index) = 0;
+
+ // Creates a bookmark folder containing a bookmark for all open tabs.
+ virtual void BookmarkAllTabs() = 0;
};
////////////////////////////////////////////////////////////////////////////////
@@ -464,6 +467,7 @@ class TabStripModel : public NotificationObserver {
CommandCloseTabsOpenedBy,
CommandRestoreTab,
CommandTogglePinned,
+ CommandBookmarkAllTabs,
CommandLast
};
diff --git a/chrome/browser/tabs/tab_strip_model_unittest.cc b/chrome/browser/tabs/tab_strip_model_unittest.cc
index 585fec5..5beb59f 100644
--- a/chrome/browser/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/tabs/tab_strip_model_unittest.cc
@@ -65,6 +65,7 @@ class TabStripDummyDelegate : public TabStripModelDelegate {
virtual bool CanRestoreTab() { return false; }
virtual void RestoreTab() {}
virtual bool CanCloseContentsAt(int index) { return can_close_ ; }
+ virtual void BookmarkAllTabs() {}
private:
// A dummy TabContents we give to callers that expect us to actually build a
diff --git a/chrome/browser/views/bookmark_editor_view.cc b/chrome/browser/views/bookmark_editor_view.cc
index bf47ec4..42d6447 100644
--- a/chrome/browser/views/bookmark_editor_view.cc
+++ b/chrome/browser/views/bookmark_editor_view.cc
@@ -87,11 +87,15 @@ BookmarkEditorView::~BookmarkEditorView() {
bool BookmarkEditorView::IsDialogButtonEnabled(
MessageBoxFlags::DialogButton button) const {
if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
+ if (IsEditingFolder())
+ return !title_tf_.text().empty();
+
const GURL url(GetInputURL());
return bb_model_->IsLoaded() && url.is_valid();
}
return true;
}
+
bool BookmarkEditorView::IsModal() const {
return true;
}
@@ -263,7 +267,7 @@ void BookmarkEditorView::Init() {
title_tf_.SetController(this);
std::wstring url_text;
- if (node_) {
+ if (node_ && !IsEditingFolder()) {
std::wstring languages = profile_
? profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)
: std::wstring();
@@ -271,7 +275,7 @@ void BookmarkEditorView::Init() {
// false and unescape=false to show the original URL except IDN.
url_text =
net::FormatUrl(node_->GetURL(), languages, false, UnescapeRule::NONE,
- NULL, NULL);
+ NULL, NULL);
}
url_tf_.SetText(url_text);
url_tf_.SetController(this);
@@ -323,12 +327,14 @@ void BookmarkEditorView::Init() {
new Label(l10n_util::GetString(IDS_BOOMARK_EDITOR_NAME_LABEL)));
layout->AddView(&title_tf_);
- layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+ if (!IsEditingFolder()) {
+ layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- layout->StartRow(0, labels_column_set_id);
- layout->AddView(
- new Label(l10n_util::GetString(IDS_BOOMARK_EDITOR_URL_LABEL)));
- layout->AddView(&url_tf_);
+ layout->StartRow(0, labels_column_set_id);
+ layout->AddView(
+ new Label(l10n_util::GetString(IDS_BOOMARK_EDITOR_URL_LABEL)));
+ layout->AddView(&url_tf_);
+ }
if (show_tree_) {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
@@ -441,12 +447,15 @@ BookmarkEditorView::EditorNode* BookmarkEditorView::AddNewGroup(
return new_node;
}
+bool BookmarkEditorView::IsEditingFolder() const {
+ return node_ && node_->is_folder();
+}
+
void BookmarkEditorView::ExpandAndSelect() {
tree_view_->ExpandAll();
const BookmarkNode* to_select = node_ ? node_->GetParent() : parent_;
int64 group_id_to_select = to_select->id();
- DCHECK(group_id_to_select); // GetMostRecentParent should never return NULL.
EditorNode* b_node =
FindNodeWithID(tree_model_->GetRoot(), group_id_to_select);
if (!b_node)
@@ -469,9 +478,10 @@ void BookmarkEditorView::CreateNodes(const BookmarkNode* bb_node,
BookmarkEditorView::EditorNode* b_node) {
for (int i = 0; i < bb_node->GetChildCount(); ++i) {
const BookmarkNode* child_bb_node = bb_node->GetChild(i);
- if (child_bb_node->is_folder()) {
+ if (child_bb_node->is_folder() &&
+ (!IsEditingFolder() || child_bb_node != node_)) {
EditorNode* new_b_node = new EditorNode(child_bb_node->GetTitle(),
- child_bb_node->id());
+ child_bb_node->id());
b_node->Add(b_node->GetChildCount(), new_b_node);
CreateNodes(child_bb_node, new_b_node);
}
diff --git a/chrome/browser/views/bookmark_editor_view.h b/chrome/browser/views/bookmark_editor_view.h
index 0b1ae90..571c9ff 100644
--- a/chrome/browser/views/bookmark_editor_view.h
+++ b/chrome/browser/views/bookmark_editor_view.h
@@ -22,13 +22,16 @@ class NativeButton;
class Window;
}
+class BookmarkEditorViewTest;
class GURL;
class Menu;
class Profile;
// View that allows the user to edit a bookmark/starred URL. The user can
// change the URL, title and where the bookmark appears as well as adding
-// new groups and changing the name of other groups.
+// new groups and changing the name of other groups. The editor is used for
+// both editing a url bookmark, as well as editing a folder bookmark when
+// created from 'Bookmark all tabs'.
//
// Edits are applied to the BookmarkModel when the user presses 'OK'.
//
@@ -43,17 +46,27 @@ class BookmarkEditorView : public BookmarkEditor,
public views::ContextMenuController,
public views::SimpleMenuModel::Delegate,
public BookmarkModelObserver {
- FRIEND_TEST(BookmarkEditorViewTest, ChangeParent);
- FRIEND_TEST(BookmarkEditorViewTest, ChangeParentAndURL);
- FRIEND_TEST(BookmarkEditorViewTest, ChangeURLToExistingURL);
- FRIEND_TEST(BookmarkEditorViewTest, EditTitleKeepsPosition);
- FRIEND_TEST(BookmarkEditorViewTest, EditURLKeepsPosition);
- FRIEND_TEST(BookmarkEditorViewTest, ModelsMatch);
- FRIEND_TEST(BookmarkEditorViewTest, MoveToNewParent);
- FRIEND_TEST(BookmarkEditorViewTest, NewURL);
- FRIEND_TEST(BookmarkEditorViewTest, ChangeURLNoTree);
- FRIEND_TEST(BookmarkEditorViewTest, ChangeTitleNoTree);
public:
+ // Type of node in the tree. Public purely for testing.
+ typedef TreeNodeWithValue<int64> EditorNode;
+
+ // Model for the TreeView. Trivial subclass that doesn't allow titles with
+ // empty strings. Public purely for testing.
+ class EditorTreeModel : public TreeNodeModel<EditorNode> {
+ public:
+ explicit EditorTreeModel(EditorNode* root)
+ : TreeNodeModel<EditorNode>(root) {}
+
+ virtual void SetTitle(TreeModelNode* node,
+ const std::wstring& title) {
+ if (!title.empty())
+ TreeNodeModel::SetTitle(node, title);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(EditorTreeModel);
+ };
+
BookmarkEditorView(Profile* profile,
const BookmarkNode* parent,
const BookmarkNode* node,
@@ -113,25 +126,7 @@ class BookmarkEditorView : public BookmarkEditor,
bool is_mouse_gesture);
private:
- // Type of node in the tree.
- typedef TreeNodeWithValue<int64> EditorNode;
-
- // Model for the TreeView. Trivial subclass that doesn't allow titles with
- // empty strings.
- class EditorTreeModel : public TreeNodeModel<EditorNode> {
- public:
- explicit EditorTreeModel(EditorNode* root)
- : TreeNodeModel<EditorNode>(root) {}
-
- virtual void SetTitle(TreeModelNode* node,
- const std::wstring& title) {
- if (!title.empty())
- TreeNodeModel::SetTitle(node, title);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EditorTreeModel);
- };
+ friend class BookmarkEditorViewTest;
// Creates the necessary sub-views, configures them, adds them to the layout,
// and requests the entries to display from the database.
@@ -172,7 +167,7 @@ class BookmarkEditorView : public BookmarkEditor,
EditorNode* CreateRootNode();
// Adds and creates a child node in b_node for all children of bb_node that
- // are groups.
+ // are groups, except for |node_| if editing a folder.
void CreateNodes(const BookmarkNode* bb_node, EditorNode* b_node);
// Returns the node with the specified id, or NULL if one can't be found.
@@ -220,6 +215,9 @@ class BookmarkEditorView : public BookmarkEditor,
// internally by NewGroup and broken into a separate method for testing.
EditorNode* AddNewGroup(EditorNode* parent);
+ // Returns true if editing a folder.
+ bool IsEditingFolder() const;
+
// Profile the entry is from.
Profile* profile_;
diff --git a/chrome/browser/views/bookmark_editor_view_unittest.cc b/chrome/browser/views/bookmark_editor_view_unittest.cc
index 22570bb..789e1ee1 100644
--- a/chrome/browser/views/bookmark_editor_view_unittest.cc
+++ b/chrome/browser/views/bookmark_editor_view_unittest.cc
@@ -49,6 +49,40 @@ class BookmarkEditorViewTest : public testing::Test {
return const_cast<BookmarkNode*>(GetNode(name));
}
+ BookmarkEditorView::EditorTreeModel* editor_tree_model() {
+ return editor_->tree_model_.get();
+ }
+
+ void CreateEditor(Profile* profile,
+ const BookmarkNode* parent,
+ const BookmarkNode* node,
+ BookmarkEditor::Configuration configuration,
+ BookmarkEditor::Handler* handler) {
+ editor_.reset(new BookmarkEditorView(profile, parent, node, configuration,
+ handler));
+ }
+
+ void SetTitleText(const std::wstring& title) {
+ editor_->title_tf_.SetText(title);
+ }
+
+ void SetURLText(const std::wstring& text) {
+ editor_->url_tf_.SetText(text);
+ }
+
+ void ApplyEdits(BookmarkEditorView::EditorNode* node) {
+ editor_->ApplyEdits(node);
+ }
+
+ BookmarkEditorView::EditorNode* AddNewGroup(
+ BookmarkEditorView::EditorNode* parent) {
+ return editor_->AddNewGroup(parent);
+ }
+
+ bool URLTFHasParent() {
+ return editor_->url_tf_.GetParent();
+ }
+
private:
// Creates the following structure:
// bookmark bar node
@@ -81,13 +115,15 @@ class BookmarkEditorViewTest : public testing::Test {
model_->AddGroup(model_->other_node(), 1, L"OF1");
model_->AddURL(of1, 0, L"of1a", GURL(test_base + "of1a"));
}
+
+ scoped_ptr<BookmarkEditorView> editor_;
};
// Makes sure the tree model matches that of the bookmark bar model.
TEST_F(BookmarkEditorViewTest, ModelsMatch) {
- BookmarkEditorView editor(profile_.get(), NULL, NULL,
- BookmarkEditorView::SHOW_TREE, NULL);
- BookmarkEditorView::EditorNode* editor_root = editor.tree_model_->GetRoot();
+ CreateEditor(profile_.get(), NULL, NULL, BookmarkEditorView::SHOW_TREE,
+ NULL);
+ BookmarkEditorView::EditorNode* editor_root = editor_tree_model()->GetRoot();
// The root should have two children, one for the bookmark bar node,
// the other for the 'other bookmarks' folder.
ASSERT_EQ(2, editor_root->GetChildCount());
@@ -110,11 +146,11 @@ TEST_F(BookmarkEditorViewTest, ModelsMatch) {
// Changes the title and makes sure parent/visual order doesn't change.
TEST_F(BookmarkEditorViewTest, EditTitleKeepsPosition) {
- BookmarkEditorView editor(profile_.get(), NULL, GetNode("a"),
- BookmarkEditorView::SHOW_TREE, NULL);
- editor.title_tf_.SetText(L"new_a");
+ CreateEditor(profile_.get(), NULL, GetNode("a"),
+ BookmarkEditorView::SHOW_TREE, NULL);
+ SetTitleText(L"new_a");
- editor.ApplyEdits(editor.tree_model_->GetRoot()->GetChild(0));
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
@@ -127,12 +163,12 @@ TEST_F(BookmarkEditorViewTest, EditTitleKeepsPosition) {
TEST_F(BookmarkEditorViewTest, EditURLKeepsPosition) {
Time node_time = Time::Now() + TimeDelta::FromDays(2);
GetMutableNode("a")->set_date_added(node_time);
- BookmarkEditorView editor(profile_.get(), NULL, GetNode("a"),
- BookmarkEditorView::SHOW_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, GetNode("a"),
+ BookmarkEditorView::SHOW_TREE, NULL);
- editor.url_tf_.SetText(UTF8ToWide(GURL(base_path() + "new_a").spec()));
+ SetURLText(UTF8ToWide(GURL(base_path() + "new_a").spec()));
- editor.ApplyEdits(editor.tree_model_->GetRoot()->GetChild(0));
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
@@ -144,10 +180,10 @@ TEST_F(BookmarkEditorViewTest, EditURLKeepsPosition) {
// Moves 'a' to be a child of the other node.
TEST_F(BookmarkEditorViewTest, ChangeParent) {
- BookmarkEditorView editor(profile_.get(), NULL, GetNode("a"),
- BookmarkEditorView::SHOW_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, GetNode("a"),
+ BookmarkEditorView::SHOW_TREE, NULL);
- editor.ApplyEdits(editor.tree_model_->GetRoot()->GetChild(1));
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
ASSERT_EQ(L"a", other_node->GetChild(2)->GetTitle());
@@ -158,12 +194,12 @@ TEST_F(BookmarkEditorViewTest, ChangeParent) {
TEST_F(BookmarkEditorViewTest, ChangeParentAndURL) {
Time node_time = Time::Now() + TimeDelta::FromDays(2);
GetMutableNode("a")->set_date_added(node_time);
- BookmarkEditorView editor(profile_.get(), NULL, GetNode("a"),
- BookmarkEditorView::SHOW_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, GetNode("a"),
+ BookmarkEditorView::SHOW_TREE, NULL);
- editor.url_tf_.SetText(UTF8ToWide(GURL(base_path() + "new_a").spec()));
+ SetURLText(UTF8ToWide(GURL(base_path() + "new_a").spec()));
- editor.ApplyEdits(editor.tree_model_->GetRoot()->GetChild(1));
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
ASSERT_EQ(L"a", other_node->GetChild(2)->GetTitle());
@@ -173,19 +209,19 @@ TEST_F(BookmarkEditorViewTest, ChangeParentAndURL) {
// Creates a new folder and moves a node to it.
TEST_F(BookmarkEditorViewTest, MoveToNewParent) {
- BookmarkEditorView editor(profile_.get(), NULL, GetNode("a"),
- BookmarkEditorView::SHOW_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, GetNode("a"),
+ BookmarkEditorView::SHOW_TREE, NULL);
// Create two nodes: "F21" as a child of "F2" and "F211" as a child of "F21".
BookmarkEditorView::EditorNode* f2 =
- editor.tree_model_->GetRoot()->GetChild(0)->GetChild(1);
- BookmarkEditorView::EditorNode* f21 = editor.AddNewGroup(f2);
+ editor_tree_model()->GetRoot()->GetChild(0)->GetChild(1);
+ BookmarkEditorView::EditorNode* f21 = AddNewGroup(f2);
f21->SetTitle(L"F21");
- BookmarkEditorView::EditorNode* f211 = editor.AddNewGroup(f21);
+ BookmarkEditorView::EditorNode* f211 = AddNewGroup(f21);
f211->SetTitle(L"F211");
// Parent the node to "F21".
- editor.ApplyEdits(f2);
+ ApplyEdits(f2);
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
@@ -206,13 +242,13 @@ TEST_F(BookmarkEditorViewTest, MoveToNewParent) {
// Brings up the editor, creating a new URL on the bookmark bar.
TEST_F(BookmarkEditorViewTest, NewURL) {
- BookmarkEditorView editor(profile_.get(), NULL, NULL,
- BookmarkEditorView::SHOW_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, NULL, BookmarkEditorView::SHOW_TREE,
+ NULL);
- editor.url_tf_.SetText(UTF8ToWide(GURL(base_path() + "a").spec()));
- editor.title_tf_.SetText(L"new_a");
+ SetURLText(UTF8ToWide(GURL(base_path() + "a").spec()));
+ SetTitleText(L"new_a");
- editor.ApplyEdits(editor.tree_model_->GetRoot()->GetChild(0));
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));
const BookmarkNode* bb_node =
profile_->GetBookmarkModel()->GetBookmarkBarNode();
@@ -226,14 +262,13 @@ TEST_F(BookmarkEditorViewTest, NewURL) {
// Brings up the editor with no tree and modifies the url.
TEST_F(BookmarkEditorViewTest, ChangeURLNoTree) {
- BookmarkEditorView editor(profile_.get(), NULL,
- model_->other_node()->GetChild(0),
- BookmarkEditorView::NO_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, model_->other_node()->GetChild(0),
+ BookmarkEditorView::NO_TREE, NULL);
- editor.url_tf_.SetText(UTF8ToWide(GURL(base_path() + "a").spec()));
- editor.title_tf_.SetText(L"new_a");
+ SetURLText(UTF8ToWide(GURL(base_path() + "a").spec()));
+ SetTitleText(L"new_a");
- editor.ApplyEdits(NULL);
+ ApplyEdits(NULL);
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
ASSERT_EQ(2, other_node->GetChildCount());
@@ -246,13 +281,12 @@ TEST_F(BookmarkEditorViewTest, ChangeURLNoTree) {
// Brings up the editor with no tree and modifies only the title.
TEST_F(BookmarkEditorViewTest, ChangeTitleNoTree) {
- BookmarkEditorView editor(profile_.get(), NULL,
- model_->other_node()->GetChild(0),
- BookmarkEditorView::NO_TREE, NULL);
+ CreateEditor(profile_.get(), NULL, model_->other_node()->GetChild(0),
+ BookmarkEditorView::NO_TREE, NULL);
- editor.title_tf_.SetText(L"new_a");
+ SetTitleText(L"new_a");
- editor.ApplyEdits(NULL);
+ ApplyEdits(NULL);
const BookmarkNode* other_node = profile_->GetBookmarkModel()->other_node();
ASSERT_EQ(2, other_node->GetChildCount());
@@ -261,3 +295,63 @@ TEST_F(BookmarkEditorViewTest, ChangeTitleNoTree) {
EXPECT_EQ(L"new_a", new_node->GetTitle());
}
+
+// Modifies the title of a folder.
+TEST_F(BookmarkEditorViewTest, ModifyFolderTitle) {
+ int64 start_id = model_->GetBookmarkBarNode()->GetChild(2)->id();
+ CreateEditor(profile_.get(), NULL, model_->GetBookmarkBarNode()->GetChild(2),
+ BookmarkEditorView::SHOW_TREE, NULL);
+
+ // The url field shouldn't be visible.
+ EXPECT_FALSE(URLTFHasParent());
+ SetTitleText(L"new_F");
+
+ // Make sure the tree isn't showing the folder we're editing.
+ EXPECT_EQ(1, editor_tree_model()->GetRoot()->GetChild(0)->GetChildCount());
+
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));
+
+ // Make sure the folder we edited is still there.
+ ASSERT_EQ(3, model_->GetBookmarkBarNode()->GetChildCount());
+ EXPECT_EQ(start_id, model_->GetBookmarkBarNode()->GetChild(2)->id());
+ EXPECT_TRUE(model_->GetBookmarkBarNode()->GetChild(2)->is_folder());
+ EXPECT_EQ(L"new_F", model_->GetBookmarkBarNode()->GetChild(2)->GetTitle());
+}
+
+// Moves a folder.
+TEST_F(BookmarkEditorViewTest, MoveFolder) {
+ const BookmarkNode* node = model_->GetBookmarkBarNode()->GetChild(2);
+ int64 start_id = node->id();
+ CreateEditor(profile_.get(), NULL, node, BookmarkEditorView::SHOW_TREE, NULL);
+
+ SetTitleText(L"new_F");
+
+ // Moves to the 'other' folder.
+ ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));
+
+ // Make sure the folder we edited is still there.
+ ASSERT_EQ(3, model_->other_node()->GetChildCount());
+ EXPECT_EQ(node, model_->other_node()->GetChild(2));
+ EXPECT_TRUE(node->is_folder());
+ EXPECT_EQ(L"new_F", node->GetTitle());
+}
+
+// Moves a folder under a new folder.
+TEST_F(BookmarkEditorViewTest, MoveFolderNewParent) {
+ const BookmarkNode* node = model_->GetBookmarkBarNode()->GetChild(2);
+ CreateEditor(profile_.get(), NULL, node, BookmarkEditorView::SHOW_TREE, NULL);
+
+ BookmarkEditorView::EditorNode* other =
+ editor_tree_model()->GetRoot()->GetChild(1);
+ BookmarkEditorView::EditorNode* new_f = AddNewGroup(other);
+ new_f->SetTitle(L"new_f");
+
+ ApplyEdits(new_f);
+
+ // Make sure the folder we edited is still there.
+ ASSERT_EQ(3, model_->other_node()->GetChildCount());
+ const BookmarkNode* new_folder = model_->other_node()->GetChild(2);
+ EXPECT_EQ(L"new_f", new_folder->GetTitle());
+ ASSERT_EQ(1, new_folder->GetChildCount());
+ ASSERT_EQ(node, new_folder->GetChild(0));
+}
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc
index 93d5cb2..9ff31b0 100644
--- a/chrome/browser/views/tabs/tab.cc
+++ b/chrome/browser/views/tabs/tab.cc
@@ -85,6 +85,8 @@ class Tab::TabContextMenuContents : public views::SimpleMenuModel,
AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD);
AddItemWithStringId(TabStripModel::CommandDuplicate,
IDS_TAB_CXMENU_DUPLICATE);
+ AddCheckItemWithStringId(TabStripModel::CommandTogglePinned,
+ IDS_TAB_CXMENU_PIN_TAB);
AddSeparator();
AddItemWithStringId(TabStripModel::CommandCloseTab,
IDS_TAB_CXMENU_CLOSETAB);
@@ -94,10 +96,12 @@ class Tab::TabContextMenuContents : public views::SimpleMenuModel,
IDS_TAB_CXMENU_CLOSETABSTORIGHT);
AddItemWithStringId(TabStripModel::CommandCloseTabsOpenedBy,
IDS_TAB_CXMENU_CLOSETABSOPENEDBY);
- AddItemWithStringId(TabStripModel::CommandRestoreTab, IDS_RESTORE_TAB);
AddSeparator();
- AddCheckItemWithStringId(TabStripModel::CommandTogglePinned,
- IDS_TAB_CXMENU_PIN_TAB);
+ AddItemWithStringId(TabStripModel::CommandRestoreTab, IDS_RESTORE_TAB);
+#if defined(OS_WIN)
+ AddItemWithStringId(TabStripModel::CommandBookmarkAllTabs,
+ IDS_TAB_CXMENU_BOOKMARK_ALL_TABS);
+#endif
menu_.reset(new views::Menu2(this));
}