Commit c749d1a7 authored by Leonard Grey's avatar Leonard Grey Committed by Commit Bot

Track bookmark bar buttons independently of the parent's hierarchy

Currently, the bookmark bar uses the view hierarchy as its "model":
bookmark buttons are force ordered to the child view index that
matches their order in the model node (so that child_at(i) is the
ith button), and GetBookmarkButtonCount() is implemented as:

`return child_count() - 6;`

This is fragile, and less than ideal for keyboard traversal.

This change tracks the buttons separately in a vector, and maintains
proper focus traversal.

This is setup for Cocoa-style button dragging (as well as a fix
for issue 841785).

Bug: 712248, 841785
Change-Id: I236e34503d021ff0f27974f731f6abcb4d62f829
Reviewed-on: https://chromium-review.googlesource.com/1177908
Commit-Queue: Leonard Grey <lgrey@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584117}
parent 8d8b1e09
...@@ -726,7 +726,7 @@ const BookmarkNode* BookmarkBarView::GetNodeForButtonAtModelIndex( ...@@ -726,7 +726,7 @@ const BookmarkNode* BookmarkBarView::GetNodeForButtonAtModelIndex(
// Then check the bookmark buttons. // Then check the bookmark buttons.
for (int i = 0; i < GetBookmarkButtonCount(); ++i) { for (int i = 0; i < GetBookmarkButtonCount(); ++i) {
views::View* child = child_at(i); views::View* child = GetBookmarkButton(i);
if (!child->visible()) if (!child->visible())
break; break;
if (child->bounds().Contains(adjusted_loc)) if (child->bounds().Contains(adjusted_loc))
...@@ -760,7 +760,7 @@ views::MenuButton* BookmarkBarView::GetMenuButtonForNode( ...@@ -760,7 +760,7 @@ views::MenuButton* BookmarkBarView::GetMenuButtonForNode(
int index = model_->bookmark_bar_node()->GetIndexOf(node); int index = model_->bookmark_bar_node()->GetIndexOf(node);
if (index == -1 || !node->is_folder()) if (index == -1 || !node->is_folder())
return nullptr; return nullptr;
return static_cast<views::MenuButton*>(child_at(index)); return static_cast<views::MenuButton*>(GetBookmarkButton(index));
} }
views::LabelButton* BookmarkBarView::GetBookmarkButtonForNode( views::LabelButton* BookmarkBarView::GetBookmarkButtonForNode(
...@@ -1007,11 +1007,11 @@ void BookmarkBarView::Layout() { ...@@ -1007,11 +1007,11 @@ void BookmarkBarView::Layout() {
if (!last_visible || !model_->loaded() || if (!last_visible || !model_->loaded() ||
model_->bookmark_bar_node()->child_count() <= button_count) model_->bookmark_bar_node()->child_count() <= button_count)
break; break;
AddChildViewAt( InsertBookmarkButtonAtIndex(
CreateBookmarkButton(model_->bookmark_bar_node()->GetChild(i)), i); CreateBookmarkButton(model_->bookmark_bar_node()->GetChild(i)), i);
button_count = GetBookmarkButtonCount(); button_count = GetBookmarkButtonCount();
} }
views::View* child = child_at(i); views::View* child = GetBookmarkButton(i);
gfx::Size pref = child->GetPreferredSize(); gfx::Size pref = child->GetPreferredSize();
int next_x = x + pref.width() + bookmark_bar_button_padding; int next_x = x + pref.width() + bookmark_bar_button_padding;
last_visible = next_x < max_x; last_visible = next_x < max_x;
...@@ -1389,8 +1389,10 @@ void BookmarkBarView::BookmarkAllUserNodesRemoved( ...@@ -1389,8 +1389,10 @@ void BookmarkBarView::BookmarkAllUserNodesRemoved(
StopThrobbing(true); StopThrobbing(true);
// Remove the existing buttons. // Remove the existing buttons.
while (GetBookmarkButtonCount()) for (views::LabelButton* button : bookmark_buttons_) {
delete GetBookmarkButton(0); delete button;
}
bookmark_buttons_.clear();
LayoutAndPaint(); LayoutAndPaint();
} }
...@@ -1406,12 +1408,14 @@ void BookmarkBarView::BookmarkNodeChildrenReordered(BookmarkModel* model, ...@@ -1406,12 +1408,14 @@ void BookmarkBarView::BookmarkNodeChildrenReordered(BookmarkModel* model,
return; // We only care about reordering of the bookmark bar node. return; // We only care about reordering of the bookmark bar node.
// Remove the existing buttons. // Remove the existing buttons.
while (GetBookmarkButtonCount()) for (views::LabelButton* button : bookmark_buttons_) {
delete child_at(0); delete button;
}
bookmark_buttons_.clear();
// Create the new buttons. // Create the new buttons.
for (int i = 0, child_count = node->child_count(); i < child_count; ++i) for (int i = 0, child_count = node->child_count(); i < child_count; ++i)
AddChildViewAt(CreateBookmarkButton(node->GetChild(i)), i); InsertBookmarkButtonAtIndex(CreateBookmarkButton(node->GetChild(i)), i);
LayoutAndPaint(); LayoutAndPaint();
} }
...@@ -1511,7 +1515,7 @@ void BookmarkBarView::OnMenuButtonClicked(views::MenuButton* view, ...@@ -1511,7 +1515,7 @@ void BookmarkBarView::OnMenuButtonClicked(views::MenuButton* view,
node = model_->bookmark_bar_node(); node = model_->bookmark_bar_node();
start_index = GetFirstHiddenNodeIndex(); start_index = GetFirstHiddenNodeIndex();
} else { } else {
int button_index = GetIndexOf(view); int button_index = GetIndexForButton(view);
DCHECK_NE(-1, button_index); DCHECK_NE(-1, button_index);
node = model_->bookmark_bar_node()->GetChild(button_index); node = model_->bookmark_bar_node()->GetChild(button_index);
} }
...@@ -1549,7 +1553,7 @@ void BookmarkBarView::ButtonPressed(views::Button* sender, ...@@ -1549,7 +1553,7 @@ void BookmarkBarView::ButtonPressed(views::Button* sender,
return; return;
} }
int index = GetIndexOf(sender); int index = GetIndexForButton(sender);
DCHECK_NE(-1, index); DCHECK_NE(-1, index);
const BookmarkNode* node = model_->bookmark_bar_node()->GetChild(index); const BookmarkNode* node = model_->bookmark_bar_node()->GetChild(index);
DCHECK(page_navigator_); DCHECK(page_navigator_);
...@@ -1588,7 +1592,7 @@ void BookmarkBarView::ShowContextMenuForView(views::View* source, ...@@ -1588,7 +1592,7 @@ void BookmarkBarView::ShowContextMenuForView(views::View* source,
// User clicked on one of the bookmark buttons, find which one they // User clicked on one of the bookmark buttons, find which one they
// clicked on, except for the apps page shortcut, which must behave as if // clicked on, except for the apps page shortcut, which must behave as if
// the user clicked on the bookmark bar background. // the user clicked on the bookmark bar background.
int bookmark_button_index = GetIndexOf(source); int bookmark_button_index = GetIndexForButton(source);
DCHECK(bookmark_button_index != -1 && DCHECK(bookmark_button_index != -1 &&
bookmark_button_index < GetBookmarkButtonCount()); bookmark_button_index < GetBookmarkButtonCount());
const BookmarkNode* node = const BookmarkNode* node =
...@@ -1618,6 +1622,14 @@ void BookmarkBarView::Init() { ...@@ -1618,6 +1622,14 @@ void BookmarkBarView::Init() {
// Child views are traversed in the order they are added. Make sure the order // Child views are traversed in the order they are added. Make sure the order
// they are added matches the visual order. // they are added matches the visual order.
apps_page_shortcut_ = CreateAppsPageShortcutButton();
AddChildView(apps_page_shortcut_);
managed_bookmarks_button_ = CreateManagedBookmarksButton();
// Also re-enabled when the model is loaded.
managed_bookmarks_button_->SetEnabled(false);
AddChildView(managed_bookmarks_button_);
overflow_button_ = CreateOverflowButton(); overflow_button_ = CreateOverflowButton();
AddChildView(overflow_button_); AddChildView(overflow_button_);
...@@ -1626,13 +1638,6 @@ void BookmarkBarView::Init() { ...@@ -1626,13 +1638,6 @@ void BookmarkBarView::Init() {
other_bookmarks_button_->SetEnabled(false); other_bookmarks_button_->SetEnabled(false);
AddChildView(other_bookmarks_button_); AddChildView(other_bookmarks_button_);
managed_bookmarks_button_ = CreateManagedBookmarksButton();
// Also re-enabled when the model is loaded.
managed_bookmarks_button_->SetEnabled(false);
AddChildView(managed_bookmarks_button_);
apps_page_shortcut_ = CreateAppsPageShortcutButton();
AddChildView(apps_page_shortcut_);
profile_pref_registrar_.Init(browser_->profile()->GetPrefs()); profile_pref_registrar_.Init(browser_->profile()->GetPrefs());
profile_pref_registrar_.Add( profile_pref_registrar_.Add(
bookmarks::prefs::kShowAppsShortcutInBookmarkBar, bookmarks::prefs::kShowAppsShortcutInBookmarkBar,
...@@ -1666,16 +1671,13 @@ void BookmarkBarView::Init() { ...@@ -1666,16 +1671,13 @@ void BookmarkBarView::Init() {
} }
int BookmarkBarView::GetBookmarkButtonCount() const { int BookmarkBarView::GetBookmarkButtonCount() const {
// We contain seven non-bookmark button views: managed bookmarks, other return bookmark_buttons_.size();
// bookmarks, bookmarks separator, chevrons (for overflow), apps page, and the
// instruction label.
return child_count() - 6;
} }
views::LabelButton* BookmarkBarView::GetBookmarkButton(int index) { views::LabelButton* BookmarkBarView::GetBookmarkButton(int index) {
// CHECK as otherwise we may do the wrong cast. // CHECK as otherwise we may do the wrong cast.
CHECK(index >= 0 && index < GetBookmarkButtonCount()); CHECK(index >= 0 && index < GetBookmarkButtonCount());
return static_cast<views::LabelButton*>(child_at(index)); return bookmark_buttons_[index];
} }
BookmarkLaunchLocation BookmarkBarView::GetBookmarkLaunchLocation() const { BookmarkLaunchLocation BookmarkBarView::GetBookmarkLaunchLocation() const {
...@@ -1729,15 +1731,15 @@ MenuButton* BookmarkBarView::CreateOverflowButton() { ...@@ -1729,15 +1731,15 @@ MenuButton* BookmarkBarView::CreateOverflowButton() {
} }
views::View* BookmarkBarView::CreateBookmarkButton(const BookmarkNode* node) { views::View* BookmarkBarView::CreateBookmarkButton(const BookmarkNode* node) {
int index = node->parent()->GetIndexOf(node);
views::LabelButton* button = nullptr;
if (node->is_url()) { if (node->is_url()) {
BookmarkButton* button = button = new BookmarkButton(this, node->url(), node->GetTitle());
new BookmarkButton(this, node->url(), node->GetTitle()); } else {
ConfigureButton(node, button); button = new BookmarkFolderButton(node->GetTitle(), this, false);
return button;
} }
views::MenuButton* button =
new BookmarkFolderButton(node->GetTitle(), this, false);
ConfigureButton(node, button); ConfigureButton(node, button);
bookmark_buttons_.insert(bookmark_buttons_.cbegin() + index, button);
return button; return button;
} }
...@@ -1815,7 +1817,7 @@ bool BookmarkBarView::BookmarkNodeAddedImpl(BookmarkModel* model, ...@@ -1815,7 +1817,7 @@ bool BookmarkBarView::BookmarkNodeAddedImpl(BookmarkModel* model,
return needs_layout_and_paint; return needs_layout_and_paint;
if (index < GetBookmarkButtonCount()) { if (index < GetBookmarkButtonCount()) {
const BookmarkNode* node = parent->GetChild(index); const BookmarkNode* node = parent->GetChild(index);
AddChildViewAt(CreateBookmarkButton(node), index); InsertBookmarkButtonAtIndex(CreateBookmarkButton(node), index);
return true; return true;
} }
// If the new node was added after the last button we've created we may be // If the new node was added after the last button we've created we may be
...@@ -1840,7 +1842,9 @@ bool BookmarkBarView::BookmarkNodeRemovedImpl(BookmarkModel* model, ...@@ -1840,7 +1842,9 @@ bool BookmarkBarView::BookmarkNodeRemovedImpl(BookmarkModel* model,
if (index >= GetBookmarkButtonCount()) if (index >= GetBookmarkButtonCount())
return needs_layout; return needs_layout;
delete child_at(index); views::LabelButton* button = GetBookmarkButton(index);
bookmark_buttons_.erase(bookmark_buttons_.cbegin() + index);
delete button;
return true; return true;
} }
...@@ -2045,7 +2049,7 @@ void BookmarkBarView::StartThrobbing(const BookmarkNode* node, ...@@ -2045,7 +2049,7 @@ void BookmarkBarView::StartThrobbing(const BookmarkNode* node,
// Node is hidden, animate the overflow button. // Node is hidden, animate the overflow button.
throbbing_view_ = overflow_button_; throbbing_view_ = overflow_button_;
} else if (!overflow_only) { } else if (!overflow_only) {
throbbing_view_ = static_cast<Button*>(child_at(index)); throbbing_view_ = static_cast<Button*>(GetBookmarkButton(index));
} }
} else if (bookmarks::IsDescendantOf(node, managed_->managed_node())) { } else if (bookmarks::IsDescendantOf(node, managed_->managed_node())) {
throbbing_view_ = managed_bookmarks_button_; throbbing_view_ = managed_bookmarks_button_;
...@@ -2077,7 +2081,7 @@ views::Button* BookmarkBarView::DetermineViewToThrobFromRemove( ...@@ -2077,7 +2081,7 @@ views::Button* BookmarkBarView::DetermineViewToThrobFromRemove(
// Node is hidden, animate the overflow button. // Node is hidden, animate the overflow button.
return overflow_button_; return overflow_button_;
} }
return static_cast<Button*>(child_at(old_index_on_bb)); return static_cast<Button*>(GetBookmarkButton(old_index_on_bb));
} }
if (bookmarks::IsDescendantOf(parent, managed_->managed_node())) if (bookmarks::IsDescendantOf(parent, managed_->managed_node()))
return managed_bookmarks_button_; return managed_bookmarks_button_;
...@@ -2163,3 +2167,35 @@ void BookmarkBarView::OnShowManagedBookmarksPrefChanged() { ...@@ -2163,3 +2167,35 @@ void BookmarkBarView::OnShowManagedBookmarksPrefChanged() {
if (UpdateOtherAndManagedButtonsVisibility()) if (UpdateOtherAndManagedButtonsVisibility())
LayoutAndPaint(); LayoutAndPaint();
} }
void BookmarkBarView::InsertBookmarkButtonAtIndex(views::View* button,
int index) {
int offset = GetIndexOf(managed_bookmarks_button_) + 1;
// All of the secondary buttons are always in the view hierarchy, even if
// they're not visible. The order should be: [Apps shortcut] [Managed bookmark
// button] ..bookmark buttons.. [Overflow chevron] [Other bookmarks]
#ifndef NDEBUG
int view_index = 0;
DCHECK_EQ(child_at(view_index++), apps_page_shortcut_);
DCHECK_EQ(child_at(view_index++), managed_bookmarks_button_);
views::View* child = nullptr;
do {
child = child_at(view_index++);
} while ((child->GetClassName() == BookmarkButton::kViewClassName ||
child->GetClassName() == BookmarkFolderButton::kViewClassName)
// Overflow and Other Bookmarks are folder buttons
&& (child != overflow_button_ && child != other_bookmarks_button_));
DCHECK_EQ(child, overflow_button_);
DCHECK_EQ(child_at(view_index++), other_bookmarks_button_);
#endif
AddChildViewAt(button, offset + index);
}
int BookmarkBarView::GetIndexForButton(views::View* button) {
auto it =
std::find(bookmark_buttons_.cbegin(), bookmark_buttons_.cend(), button);
if (it == bookmark_buttons_.cend())
return -1;
return it - bookmark_buttons_.cbegin();
}
...@@ -388,6 +388,14 @@ class BookmarkBarView : public views::AccessiblePaneView, ...@@ -388,6 +388,14 @@ class BookmarkBarView : public views::AccessiblePaneView,
SchedulePaint(); SchedulePaint();
} }
// Inserts |button| in logical position |index| in the bar, maintaining
// correct focus traversal order.
void InsertBookmarkButtonAtIndex(views::View* button, int index);
// Returns the model index for the bookmark associated with |button|,
// or -1 if |button| is not a bookmark button from this bar.
int GetIndexForButton(views::View* button);
int GetPreferredHeight() const; int GetPreferredHeight() const;
// Needed to react to kShowAppsShortcutInBookmarkBar changes. // Needed to react to kShowAppsShortcutInBookmarkBar changes.
...@@ -431,6 +439,9 @@ class BookmarkBarView : public views::AccessiblePaneView, ...@@ -431,6 +439,9 @@ class BookmarkBarView : public views::AccessiblePaneView,
// Visible if not all the bookmark buttons fit. // Visible if not all the bookmark buttons fit.
views::MenuButton* overflow_button_; views::MenuButton* overflow_button_;
// The individual bookmark buttons.
std::vector<views::LabelButton*> bookmark_buttons_;
// Shows a text and a link to import bookmarks if there are no bookmarks in // Shows a text and a link to import bookmarks if there are no bookmarks in
// the Bookmarks Bar. // the Bookmarks Bar.
views::View* instructions_; views::View* instructions_;
......
...@@ -24,6 +24,10 @@ class BookmarkBarViewTestHelper { ...@@ -24,6 +24,10 @@ class BookmarkBarViewTestHelper {
views::MenuButton* overflow_button() { return bbv_->overflow_button_; } views::MenuButton* overflow_button() { return bbv_->overflow_button_; }
views::MenuButton* managed_bookmarks_button() {
return bbv_->managed_bookmarks_button_;
}
private: private:
BookmarkBarView* bbv_; BookmarkBarView* bbv_;
......
...@@ -209,6 +209,15 @@ TEST_F(BookmarkBarViewTest, ButtonsDynamicallyAddedAfterModelHasNodes) { ...@@ -209,6 +209,15 @@ TEST_F(BookmarkBarViewTest, ButtonsDynamicallyAddedAfterModelHasNodes) {
0, 0, 5000, bookmark_bar_view_->bounds().height()); 0, 0, 5000, bookmark_bar_view_->bounds().height());
bookmark_bar_view_->Layout(); bookmark_bar_view_->Layout();
EXPECT_EQ(6, test_helper_->GetBookmarkButtonCount()); EXPECT_EQ(6, test_helper_->GetBookmarkButtonCount());
// Ensure buttons were added in the correct place.
int managed_button_index =
bookmark_bar_view_->GetIndexOf(test_helper_->managed_bookmarks_button());
for (int i = 0; i < test_helper_->GetBookmarkButtonCount(); ++i) {
views::View* button = test_helper_->GetBookmarkButton(i);
EXPECT_EQ(bookmark_bar_view_->GetIndexOf(button),
managed_button_index + 1 + i);
}
} }
// Verifies buttons are added as the model and size change. // Verifies buttons are added as the model and size change.
...@@ -225,6 +234,14 @@ TEST_F(BookmarkBarViewTest, ButtonsDynamicallyAdded) { ...@@ -225,6 +234,14 @@ TEST_F(BookmarkBarViewTest, ButtonsDynamicallyAdded) {
0, 0, 5000, bookmark_bar_view_->bounds().height()); 0, 0, 5000, bookmark_bar_view_->bounds().height());
bookmark_bar_view_->Layout(); bookmark_bar_view_->Layout();
EXPECT_EQ(6, test_helper_->GetBookmarkButtonCount()); EXPECT_EQ(6, test_helper_->GetBookmarkButtonCount());
// Ensure buttons were added in the correct place.
int managed_button_index =
bookmark_bar_view_->GetIndexOf(test_helper_->managed_bookmarks_button());
for (int i = 0; i < test_helper_->GetBookmarkButtonCount(); ++i) {
views::View* button = test_helper_->GetBookmarkButton(i);
EXPECT_EQ(bookmark_bar_view_->GetIndexOf(button),
managed_button_index + 1 + i);
}
} }
TEST_F(BookmarkBarViewTest, AddNodesWhenBarAlreadySized) { TEST_F(BookmarkBarViewTest, AddNodesWhenBarAlreadySized) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment