Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / bookmarks / bookmark_bar_view.cc
index 08973c8..8b044e7 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 #include <limits>
-#include <set>
+#include <string>
 #include <vector>
 
 #include "base/bind.h"
@@ -16,6 +16,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/chrome_bookmark_client.h"
+#include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
@@ -36,6 +38,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_instructions_view.h"
+#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view_observer.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_context_menu.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h"
@@ -47,7 +50,9 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "components/bookmarks/core/browser/bookmark_model.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/metrics/metrics_service.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/page_transition_types.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
-#include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
-#include "grit/ui_resources.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/dragdrop/drag_utils.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/page_transition_types.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/text_constants.h"
 #include "ui/gfx/text_elider.h"
+#include "ui/resources/grit/ui_resources.h"
 #include "ui/views/button_drag_utils.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/drag_utils.h"
 #include "ui/views/window/non_client_view.h"
 
 using base::UserMetricsAction;
+using bookmarks::BookmarkNodeData;
 using content::OpenURLParams;
 using content::PageNavigator;
 using content::Referrer;
 using ui::DropTargetEvent;
 using views::CustomButton;
+using views::LabelButtonBorder;
 using views::MenuButton;
 using views::View;
 
@@ -135,6 +144,20 @@ static const int kOtherFolderButtonTag = 1;
 // Tag for the 'Apps Shortcut' button.
 static const int kAppsShortcutButtonTag = 2;
 
+// Preferred padding between text and edge.
+static const int kButtonPaddingHorizontal = 6;
+static const int kButtonPaddingVertical = 4;
+
+// Tag for the 'Managed bookmarks' button.
+static const int kManagedFolderButtonTag = 3;
+
+#if !defined(OS_WIN)
+static const gfx::ElideBehavior kElideBehavior = gfx::FADE_TAIL;
+#else
+// Windows fade eliding causes text to darken; see http://crbug.com/388084
+static const gfx::ElideBehavior kElideBehavior = gfx::ELIDE_TAIL;
+#endif
+
 namespace {
 
 // To enable/disable BookmarkBar animations during testing. In production
@@ -143,13 +166,14 @@ bool animations_enabled = true;
 
 // BookmarkButtonBase -----------------------------------------------
 
-// Base class for text buttons used on the bookmark bar.
+// Base class for buttons used on the bookmark bar.
 
-class BookmarkButtonBase : public views::TextButton {
+class BookmarkButtonBase : public views::LabelButton {
  public:
   BookmarkButtonBase(views::ButtonListener* listener,
                      const base::string16& title)
-      : TextButton(listener, title) {
+      : LabelButton(listener, title) {
+    SetElideBehavior(kElideBehavior);
     show_animation_.reset(new gfx::SlideAnimation(this));
     if (!animations_enabled) {
       // For some reason during testing the events generated by animating
@@ -160,6 +184,19 @@ class BookmarkButtonBase : public views::TextButton {
     }
   }
 
+  virtual View* GetTooltipHandlerForPoint(const gfx::Point& point) OVERRIDE {
+    return HitTestPoint(point) && CanProcessEventsWithinSubtree() ? this : NULL;
+  }
+
+  virtual scoped_ptr<LabelButtonBorder> CreateDefaultBorder() const OVERRIDE {
+    scoped_ptr<LabelButtonBorder> border = LabelButton::CreateDefaultBorder();
+    border->set_insets(gfx::Insets(kButtonPaddingVertical,
+                                   kButtonPaddingHorizontal,
+                                   kButtonPaddingVertical,
+                                   kButtonPaddingHorizontal));
+    return border.Pass();
+  }
+
   virtual bool IsTriggerableEvent(const ui::Event& e) OVERRIDE {
     return e.type() == ui::ET_GESTURE_TAP ||
            e.type() == ui::ET_GESTURE_TAP_DOWN ||
@@ -195,7 +232,7 @@ class BookmarkButton : public BookmarkButtonBase {
     gfx::Point location(p);
     ConvertPointToScreen(this, &location);
     *tooltip = BookmarkBarView::CreateToolTipForURLAndTitle(
-        GetWidget(), location, url_, text(), profile_);
+        GetWidget(), location, url_, GetText(), profile_);
     return !tooltip->empty();
   }
 
@@ -232,7 +269,6 @@ class ShortcutButton : public BookmarkButtonBase {
   }
 
  private:
-
   DISALLOW_COPY_AND_ASSIGN(ShortcutButton);
 };
 
@@ -250,6 +286,7 @@ class BookmarkFolderButton : public views::MenuButton {
                        views::MenuButtonListener* menu_button_listener,
                        bool show_menu_marker)
       : MenuButton(listener, title, menu_button_listener, show_menu_marker) {
+    SetElideBehavior(kElideBehavior);
     show_animation_.reset(new gfx::SlideAnimation(this));
     if (!animations_enabled) {
       // For some reason during testing the events generated by animating
@@ -262,8 +299,8 @@ class BookmarkFolderButton : public views::MenuButton {
 
   virtual bool GetTooltipText(const gfx::Point& p,
                               base::string16* tooltip) const OVERRIDE {
-    if (text_size_.width() > GetTextBounds().width())
-      *tooltip = text_;
+    if (label()->GetPreferredSize().width() > label()->size().width())
+      *tooltip = GetText();
     return !tooltip->empty();
   }
 
@@ -281,10 +318,6 @@ class BookmarkFolderButton : public views::MenuButton {
     return false;
   }
 
-  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
-    views::MenuButton::PaintButton(canvas, views::MenuButton::PB_NORMAL);
-  }
-
  private:
   scoped_ptr<gfx::SlideAnimation> show_animation_;
 
@@ -395,7 +428,7 @@ class BookmarkBarView::ButtonSeparatorView : public views::View {
         GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR));
   }
 
-  virtual gfx::Size GetPreferredSize() OVERRIDE {
+  virtual gfx::Size GetPreferredSize() const OVERRIDE {
     // We get the full height of the bookmark bar, so that the height returned
     // here doesn't matter.
     return gfx::Size(kSeparatorWidth, 1);
@@ -417,7 +450,7 @@ const int BookmarkBarView::kMaxButtonWidth = 150;
 const int BookmarkBarView::kNewtabHorizontalPadding = 2;
 const int BookmarkBarView::kToolbarAttachedBookmarkBarOverlap = 3;
 
-static const gfx::ImageSkia& GetDefaultFavicon() {
+const gfx::ImageSkia& GetDefaultFavicon() {
   if (!kDefaultFavicon) {
     ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
     kDefaultFavicon = rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
@@ -425,7 +458,7 @@ static const gfx::ImageSkia& GetDefaultFavicon() {
   return *kDefaultFavicon;
 }
 
-static const gfx::ImageSkia& GetFolderIcon() {
+const gfx::ImageSkia& GetFolderIcon() {
   if (!kFolderIcon) {
     ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
     kFolderIcon = rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_FOLDER);
@@ -435,12 +468,12 @@ static const gfx::ImageSkia& GetFolderIcon() {
 
 BookmarkBarView::BookmarkBarView(Browser* browser, BrowserView* browser_view)
     : page_navigator_(NULL),
-      model_(NULL),
+      client_(NULL),
       bookmark_menu_(NULL),
       bookmark_drop_menu_(NULL),
       other_bookmarked_button_(NULL),
+      managed_bookmarks_button_(NULL),
       apps_page_shortcut_(NULL),
-      show_folder_method_factory_(this),
       overflow_button_(NULL),
       instructions_(NULL),
       bookmarks_separator_view_(NULL),
@@ -449,7 +482,8 @@ BookmarkBarView::BookmarkBarView(Browser* browser, BrowserView* browser_view)
       infobar_visible_(false),
       throbbing_view_(NULL),
       bookmark_bar_state_(BookmarkBar::SHOW),
-      animating_detached_(false) {
+      animating_detached_(false),
+      show_folder_method_factory_(this) {
   set_id(VIEW_ID_BOOKMARK_BAR);
   Init();
 
@@ -478,6 +512,14 @@ void BookmarkBarView::DisableAnimationsForTesting(bool disabled) {
   animations_enabled = !disabled;
 }
 
+void BookmarkBarView::AddObserver(BookmarkBarViewObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void BookmarkBarView::RemoveObserver(BookmarkBarViewObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void BookmarkBarView::SetPageNavigator(PageNavigator* navigator) {
   page_navigator_ = navigator;
   if (bookmark_menu_)
@@ -526,7 +568,13 @@ const BookmarkNode* BookmarkBarView::GetNodeForButtonAtModelIndex(
 
   gfx::Point adjusted_loc(GetMirroredXInView(loc.x()), loc.y());
 
-  // Check the buttons first.
+  // Check the managed button first.
+  if (managed_bookmarks_button_->visible() &&
+      managed_bookmarks_button_->bounds().Contains(adjusted_loc)) {
+    return client_->managed_node();
+  }
+
+  // Then check the bookmark buttons.
   for (int i = 0; i < GetBookmarkButtonCount(); ++i) {
     views::View* child = child_at(i);
     if (!child->visible())
@@ -553,6 +601,8 @@ const BookmarkNode* BookmarkBarView::GetNodeForButtonAtModelIndex(
 
 views::MenuButton* BookmarkBarView::GetMenuButtonForNode(
     const BookmarkNode* node) {
+  if (node == client_->managed_node())
+    return managed_bookmarks_button_;
   if (node == model_->other_node())
     return other_bookmarked_button_;
   if (node == model_->bookmark_bar_node())
@@ -611,8 +661,8 @@ base::string16 BookmarkBarView::CreateToolTipForURLAndTitle(
   if (!title.empty()) {
     base::string16 localized_title = title;
     base::i18n::AdjustStringForLocaleDirection(&localized_title);
-    result.append(ElideText(localized_title, tt_fonts, max_width,
-                            gfx::ELIDE_AT_END));
+    result.append(gfx::ElideText(localized_title, tt_fonts, max_width,
+                                 gfx::ELIDE_TAIL));
   }
 
   // Only show the URL if the url and title differ.
@@ -664,27 +714,39 @@ int BookmarkBarView::GetToolbarOverlap() const {
           size_animation_->GetCurrentValue());
 }
 
-gfx::Size BookmarkBarView::GetPreferredSize() {
-  return LayoutItems(true);
+gfx::Size BookmarkBarView::GetPreferredSize() const {
+  gfx::Size prefsize;
+  if (IsDetached()) {
+    prefsize.set_height(
+        chrome::kBookmarkBarHeight +
+        static_cast<int>(
+            (chrome::kNTPBookmarkBarHeight - chrome::kBookmarkBarHeight) *
+            (1 - size_animation_->GetCurrentValue())));
+  } else {
+    prefsize.set_height(static_cast<int>(chrome::kBookmarkBarHeight *
+                                         size_animation_->GetCurrentValue()));
+  }
+  return prefsize;
 }
 
-bool BookmarkBarView::HitTestRect(const gfx::Rect& rect) const {
-  // If bookmark bar is attached and omnibox popup is open (on top of the bar),
-  // force hit-testing to fail.  This prevents hovers/clicks just above the
-  // omnibox popup from activating the top few pixels of items on the bookmark
-  // bar.
+bool BookmarkBarView::CanProcessEventsWithinSubtree() const {
+  // If the bookmark bar is attached and the omnibox popup is open (on top of
+  // the bar), prevent events from targeting the bookmark bar or any of its
+  // descendants. This will prevent hovers/clicks just above the omnibox popup
+  // from activating the top few pixels of items on the bookmark bar.
   if (!IsDetached() && browser_view_ &&
       browser_view_->GetLocationBar()->GetOmniboxView()->model()->
           popup_model()->IsOpen()) {
     return false;
   }
-  return DetachableToolbarView::HitTestRect(rect);
+  return true;
 }
 
-gfx::Size BookmarkBarView::GetMinimumSize() {
+gfx::Size BookmarkBarView::GetMinimumSize() const {
   // The minimum width of the bookmark bar should at least contain the overflow
   // button, by which one can access all the Bookmark Bar items, and the "Other
   // Bookmarks" folder, along with appropriate margins and button padding.
+  // It should also contain the Managed Bookmarks folder, if it's visible.
   int width = kLeftMargin;
 
   int height = chrome::kBookmarkBarHeight;
@@ -696,29 +758,32 @@ gfx::Size BookmarkBarView::GetMinimumSize() {
             current_state);
   }
 
-  gfx::Size other_bookmarked_pref;
-  if (other_bookmarked_button_->visible())
-    other_bookmarked_pref = other_bookmarked_button_->GetPreferredSize();
-  gfx::Size overflow_pref;
-  if (overflow_button_->visible())
-    overflow_pref = overflow_button_->GetPreferredSize();
-  gfx::Size bookmarks_separator_pref;
-  if (bookmarks_separator_view_->visible())
-    bookmarks_separator_pref = bookmarks_separator_view_->GetPreferredSize();
-
-  gfx::Size apps_page_shortcut_pref;
-  if (apps_page_shortcut_->visible())
-    apps_page_shortcut_pref = apps_page_shortcut_->GetPreferredSize();
-  width += other_bookmarked_pref.width() + kButtonPadding +
-      apps_page_shortcut_pref.width() + kButtonPadding +
-      overflow_pref.width() + kButtonPadding +
-      bookmarks_separator_pref.width();
+  if (managed_bookmarks_button_->visible()) {
+    gfx::Size size = managed_bookmarks_button_->GetPreferredSize();
+    width += size.width() + kButtonPadding;
+  }
+  if (other_bookmarked_button_->visible()) {
+    gfx::Size size = other_bookmarked_button_->GetPreferredSize();
+    width += size.width() + kButtonPadding;
+  }
+  if (overflow_button_->visible()) {
+    gfx::Size size = overflow_button_->GetPreferredSize();
+    width += size.width() + kButtonPadding;
+  }
+  if (bookmarks_separator_view_->visible()) {
+    gfx::Size size = bookmarks_separator_view_->GetPreferredSize();
+    width += size.width();
+  }
+  if (apps_page_shortcut_->visible()) {
+    gfx::Size size = apps_page_shortcut_->GetPreferredSize();
+    width += size.width() + kButtonPadding;
+  }
 
   return gfx::Size(width, height);
 }
 
 void BookmarkBarView::Layout() {
-  LayoutItems(false);
+  LayoutItems();
 }
 
 void BookmarkBarView::ViewHierarchyChanged(
@@ -738,8 +803,9 @@ void BookmarkBarView::ViewHierarchyChanged(
   }
 }
 
-void BookmarkBarView::PaintChildren(gfx::Canvas* canvas) {
-  View::PaintChildren(canvas);
+void BookmarkBarView::PaintChildren(gfx::Canvas* canvas,
+                                    const views::CullSet& cull_set) {
+  View::PaintChildren(canvas, cull_set);
 
   if (drop_info_.get() && drop_info_->valid &&
       drop_info_->location.operation != 0 && drop_info_->location.index != -1 &&
@@ -795,7 +861,7 @@ bool BookmarkBarView::AreDropTypesRequired() {
 bool BookmarkBarView::CanDrop(const ui::OSExchangeData& data) {
   if (!model_ || !model_->loaded() ||
       !browser_->profile()->GetPrefs()->GetBoolean(
-          prefs::kEditBookmarksEnabled))
+          bookmarks::prefs::kEditBookmarksEnabled))
     return false;
 
   if (!drop_info_.get())
@@ -906,8 +972,10 @@ int BookmarkBarView::OnPerformDrop(const DropTargetEvent& event) {
   }
   const BookmarkNodeData data = drop_info_->data;
   DCHECK(data.is_valid());
+  bool copy = drop_info_->location.operation == ui::DragDropTypes::DRAG_COPY;
   drop_info_.reset();
-  return chrome::DropBookmarks(browser_->profile(), data, parent_node, index);
+  return chrome::DropBookmarks(
+      browser_->profile(), data, parent_node, index, copy);
 }
 
 void BookmarkBarView::OnThemeChanged() {
@@ -918,6 +986,15 @@ const char* BookmarkBarView::GetClassName() const {
   return kViewClassName;
 }
 
+void BookmarkBarView::SetVisible(bool v) {
+  if (v == visible())
+    return;
+
+  View::SetVisible(v);
+  FOR_EACH_OBSERVER(BookmarkBarViewObserver, observers_,
+                    OnBookmarkBarVisibilityChanged());
+}
+
 void BookmarkBarView::GetAccessibleState(ui::AXViewState* state) {
   state->role = ui::AX_ROLE_TOOLBAR;
   state->name = l10n_util::GetStringUTF16(IDS_ACCNAME_BOOKMARKS);
@@ -946,8 +1023,7 @@ void BookmarkBarView::BookmarkMenuControllerDeleted(
 }
 
 void BookmarkBarView::ShowImportDialog() {
-  int64 install_time =
-      g_browser_process->local_state()->GetInt64(prefs::kInstallDate);
+  int64 install_time = g_browser_process->metrics_service()->GetInstallDate();
   int64 time_from_install = base::Time::Now().ToTimeT() - install_time;
   if (bookmark_bar_state_ == BookmarkBar::SHOW) {
     UMA_HISTOGRAM_COUNTS("Import.ShowDialog.FromBookmarkBarView",
@@ -962,7 +1038,7 @@ void BookmarkBarView::ShowImportDialog() {
 
 void BookmarkBarView::OnBookmarkBubbleShown(const GURL& url) {
   StopThrobbing(true);
-  const BookmarkNode* node = model_->GetMostRecentlyAddedNodeForURL(url);
+  const BookmarkNode* node = model_->GetMostRecentlyAddedUserNodeForURL(url);
   if (!node)
     return;  // Generally shouldn't happen.
   StartThrobbing(node, false);
@@ -977,17 +1053,21 @@ void BookmarkBarView::BookmarkModelLoaded(BookmarkModel* model,
   // There should be no buttons. If non-zero it means Load was invoked more than
   // once, or we didn't properly clear things. Either of which shouldn't happen.
   DCHECK_EQ(0, GetBookmarkButtonCount());
-  const BookmarkNode* node = model_->bookmark_bar_node();
+  const BookmarkNode* node = model->bookmark_bar_node();
   DCHECK(node);
   // Create a button for each of the children on the bookmark bar.
   for (int i = 0, child_count = node->child_count(); i < child_count; ++i)
     AddChildViewAt(CreateBookmarkButton(node->GetChild(i)), i);
-  DCHECK(model_->other_node());
-  other_bookmarked_button_->SetAccessibleName(model_->other_node()->GetTitle());
-  other_bookmarked_button_->SetText(model_->other_node()->GetTitle());
+  DCHECK(model->other_node());
+  other_bookmarked_button_->SetAccessibleName(model->other_node()->GetTitle());
+  other_bookmarked_button_->SetText(model->other_node()->GetTitle());
+  managed_bookmarks_button_->SetAccessibleName(
+      client_->managed_node()->GetTitle());
+  managed_bookmarks_button_->SetText(client_->managed_node()->GetTitle());
   UpdateColors();
-  UpdateOtherBookmarksVisibility();
+  UpdateButtonsVisibility();
   other_bookmarked_button_->SetEnabled(true);
+  managed_bookmarks_button_->SetEnabled(true);
 
   Layout();
   SchedulePaint();
@@ -1032,10 +1112,10 @@ void BookmarkBarView::BookmarkNodeRemoved(BookmarkModel* model,
   BookmarkNodeRemovedImpl(model, parent, old_index);
 }
 
-void BookmarkBarView::BookmarkAllNodesRemoved(
+void BookmarkBarView::BookmarkAllUserNodesRemoved(
     BookmarkModel* model,
     const std::set<GURL>& removed_urls) {
-  UpdateOtherBookmarksVisibility();
+  UpdateButtonsVisibility();
 
   StopThrobbing(true);
 
@@ -1055,7 +1135,7 @@ void BookmarkBarView::BookmarkNodeChanged(BookmarkModel* model,
 
 void BookmarkBarView::BookmarkNodeChildrenReordered(BookmarkModel* model,
                                                     const BookmarkNode* node) {
-  if (node != model_->bookmark_bar_node())
+  if (node != model->bookmark_bar_node())
     return;  // We only care about reordering of the bookmark bar node.
 
   // Remove the existing buttons.
@@ -1086,13 +1166,21 @@ void BookmarkBarView::WriteDragDataForView(View* sender,
 
   for (int i = 0; i < GetBookmarkButtonCount(); ++i) {
     if (sender == GetBookmarkButton(i)) {
-      views::TextButton* button = GetBookmarkButton(i);
-      scoped_ptr<gfx::Canvas> canvas(
-          views::GetCanvasForDragImage(button->GetWidget(), button->size()));
-      button->PaintButton(canvas.get(), views::TextButton::PB_FOR_DRAG);
-      drag_utils::SetDragImageOnDataObject(*canvas, button->size(),
-                                           press_pt.OffsetFromOrigin(),
-                                           data);
+      views::LabelButton* button = GetBookmarkButton(i);
+      const BookmarkNode* node = model_->bookmark_bar_node()->GetChild(i);
+
+      const gfx::Image& image_from_model = model_->GetFavicon(node);
+      const gfx::ImageSkia& icon = image_from_model.IsEmpty() ?
+          (node->is_folder() ? GetFolderIcon() : GetDefaultFavicon()) :
+          *image_from_model.ToImageSkia();
+
+      button_drag_utils::SetDragImage(
+          node->url(),
+          node->GetTitle(),
+          icon,
+          &press_pt,
+          data,
+          button->GetWidget());
       WriteBookmarkDragData(model_->bookmark_bar_node()->GetChild(i), data);
       return;
     }
@@ -1154,6 +1242,8 @@ void BookmarkBarView::OnMenuButtonClicked(views::View* view,
   int start_index = 0;
   if (view == other_bookmarked_button_) {
     node = model_->other_node();
+  } else if (view == managed_bookmarks_button_) {
+    node = client_->managed_node();
   } else if (view == overflow_button_) {
     node = model_->bookmark_bar_node();
     start_index = GetFirstHiddenNodeIndex();
@@ -1165,9 +1255,9 @@ void BookmarkBarView::OnMenuButtonClicked(views::View* view,
 
   RecordBookmarkFolderOpen(GetBookmarkLaunchLocation());
   bookmark_menu_ = new BookmarkMenuController(
-      browser_, page_navigator_, GetWidget(), node, start_index);
+      browser_, page_navigator_, GetWidget(), node, start_index, false);
   bookmark_menu_->set_observer(this);
-  bookmark_menu_->RunMenuAt(this, false);
+  bookmark_menu_->RunMenuAt(this);
 }
 
 void BookmarkBarView::ButtonPressed(views::Button* sender,
@@ -1179,7 +1269,7 @@ void BookmarkBarView::ButtonPressed(views::Button* sender,
     OpenURLParams params(GURL(chrome::kChromeUIAppsURL),
                          Referrer(),
                          disposition_from_event_flags,
-                         content::PAGE_TRANSITION_AUTO_BOOKMARK,
+                         ui::PAGE_TRANSITION_AUTO_BOOKMARK,
                          false);
     page_navigator_->OpenURL(params);
     RecordBookmarkAppsPageOpen(GetBookmarkLaunchLocation());
@@ -1189,6 +1279,8 @@ void BookmarkBarView::ButtonPressed(views::Button* sender,
   const BookmarkNode* node;
   if (sender->tag() == kOtherFolderButtonTag) {
     node = model_->other_node();
+  } else if (sender->tag() == kManagedFolderButtonTag) {
+    node = client_->managed_node();
   } else {
     int index = GetIndexOf(sender);
     DCHECK_NE(-1, index);
@@ -1200,7 +1292,7 @@ void BookmarkBarView::ButtonPressed(views::Button* sender,
     RecordAppLaunch(browser_->profile(), node->url());
     OpenURLParams params(
         node->url(), Referrer(), disposition_from_event_flags,
-        content::PAGE_TRANSITION_AUTO_BOOKMARK, false);
+        ui::PAGE_TRANSITION_AUTO_BOOKMARK, false);
     page_navigator_->OpenURL(params);
   } else {
     chrome::OpenAll(GetWidget()->GetNativeWindow(), page_navigator_, node,
@@ -1225,6 +1317,9 @@ void BookmarkBarView::ShowContextMenuForView(views::View* source,
     // Do this so the user can open all bookmarks. BookmarkContextMenu makes
     // sure the user can't edit/delete the node in this case.
     nodes.push_back(parent);
+  } else if (source == managed_bookmarks_button_) {
+    parent = client_->managed_node();
+    nodes.push_back(parent);
   } else if (source != this && source != apps_page_shortcut_) {
     // 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
@@ -1266,13 +1361,22 @@ void BookmarkBarView::Init() {
   other_bookmarked_button_->SetEnabled(false);
   AddChildView(other_bookmarked_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_.Add(
-      prefs::kShowAppsShortcutInBookmarkBar,
+      bookmarks::prefs::kShowAppsShortcutInBookmarkBar,
       base::Bind(&BookmarkBarView::OnAppsPageShortcutVisibilityPrefChanged,
                  base::Unretained(this)));
+  profile_pref_registrar_.Add(
+      bookmarks::prefs::kShowManagedBookmarksInBookmarkBar,
+      base::Bind(&BookmarkBarView::UpdateButtonsVisibility,
+                 base::Unretained(this)));
   apps_page_shortcut_->SetVisible(
       chrome::ShouldShowAppsShortcutInBookmarkBar(
           browser_->profile(), browser_->host_desktop_type()));
@@ -1289,6 +1393,7 @@ void BookmarkBarView::Init() {
   size_animation_.reset(new gfx::SlideAnimation(this));
 
   model_ = BookmarkModelFactory::GetForProfile(browser_->profile());
+  client_ = ChromeBookmarkClientFactory::GetForProfile(browser_->profile());
   if (model_) {
     model_->AddObserver(this);
     if (model_->loaded())
@@ -1298,15 +1403,16 @@ void BookmarkBarView::Init() {
   }
 }
 
-int BookmarkBarView::GetBookmarkButtonCount() {
-  // We contain four non-bookmark button views: other bookmarks, bookmarks
-  // separator, chevrons (for overflow), apps page, and the instruction label.
-  return child_count() - 5;
+int BookmarkBarView::GetBookmarkButtonCount() const {
+  // We contain six non-bookmark button views: managed bookmarks,
+  // other bookmarks, bookmarks separator, chevrons (for overflow), apps page,
+  // and the instruction label.
+  return child_count() - 6;
 }
 
-views::TextButton* BookmarkBarView::GetBookmarkButton(int index) {
+views::LabelButton* BookmarkBarView::GetBookmarkButton(int index) {
   DCHECK(index >= 0 && index < GetBookmarkButtonCount());
-  return static_cast<views::TextButton*>(child_at(index));
+  return static_cast<views::LabelButton*>(child_at(index));
 }
 
 BookmarkLaunchLocation BookmarkBarView::GetBookmarkLaunchLocation() const {
@@ -1328,16 +1434,31 @@ MenuButton* BookmarkBarView::CreateOtherBookmarkedButton() {
   MenuButton* button =
       new BookmarkFolderButton(this, base::string16(), this, false);
   button->set_id(VIEW_ID_OTHER_BOOKMARKS);
-  button->SetIcon(GetFolderIcon());
+  button->SetImage(views::Button::STATE_NORMAL, GetFolderIcon());
   button->set_context_menu_controller(this);
   button->set_tag(kOtherFolderButtonTag);
   return button;
 }
 
+MenuButton* BookmarkBarView::CreateManagedBookmarksButton() {
+  // Title is set in Loaded.
+  MenuButton* button =
+      new BookmarkFolderButton(this, base::string16(), this, false);
+  button->set_id(VIEW_ID_MANAGED_BOOKMARKS);
+  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+  gfx::ImageSkia* image =
+      rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_FOLDER_MANAGED);
+  button->SetImage(views::Button::STATE_NORMAL, *image);
+  button->set_context_menu_controller(this);
+  button->set_tag(kManagedFolderButtonTag);
+  return button;
+}
+
 MenuButton* BookmarkBarView::CreateOverflowButton() {
   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
   MenuButton* button = new OverFlowButton(this);
-  button->SetIcon(*rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_CHEVRONS));
+  button->SetImage(views::Button::STATE_NORMAL,
+                   *rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_CHEVRONS));
 
   // The overflow button's image contains an arrow and therefore it is a
   // direction sensitive image and we need to flip it if the UI layout is
@@ -1365,54 +1486,56 @@ views::View* BookmarkBarView::CreateBookmarkButton(const BookmarkNode* node) {
   } else {
     views::MenuButton* button = new BookmarkFolderButton(
         this, node->GetTitle(), this, false);
-    button->SetIcon(GetFolderIcon());
+    button->SetImage(views::Button::STATE_NORMAL, GetFolderIcon());
     ConfigureButton(node, button);
     return button;
   }
 }
 
-views::TextButton* BookmarkBarView::CreateAppsPageShortcutButton() {
-  views::TextButton* button = new ShortcutButton(
+views::LabelButton* BookmarkBarView::CreateAppsPageShortcutButton() {
+  views::LabelButton* button = new ShortcutButton(
       this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_APPS_SHORTCUT_NAME));
   button->SetTooltipText(l10n_util::GetStringUTF16(
       IDS_BOOKMARK_BAR_APPS_SHORTCUT_TOOLTIP));
   button->set_id(VIEW_ID_BOOKMARK_BAR_ELEMENT);
   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
-  button->SetIcon(*rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_APPS_SHORTCUT));
+  button->SetImage(views::Button::STATE_NORMAL,
+                   *rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_APPS_SHORTCUT));
   button->set_context_menu_controller(this);
   button->set_tag(kAppsShortcutButtonTag);
   return button;
 }
 
 void BookmarkBarView::ConfigureButton(const BookmarkNode* node,
-                                      views::TextButton* button) {
+                                      views::LabelButton* button) {
   button->SetText(node->GetTitle());
   button->SetAccessibleName(node->GetTitle());
   button->set_id(VIEW_ID_BOOKMARK_BAR_ELEMENT);
   // We don't always have a theme provider (ui tests, for example).
   if (GetThemeProvider()) {
-    button->SetEnabledColor(GetThemeProvider()->GetColor(
-        ThemeProperties::COLOR_BOOKMARK_TEXT));
+    button->SetTextColor(
+        views::Button::STATE_NORMAL,
+        GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT));
   }
 
-  button->ClearMaxTextSize();
+  button->SetMinSize(gfx::Size());
   button->set_context_menu_controller(this);
   button->set_drag_controller(this);
   if (node->is_url()) {
     const gfx::Image& favicon = model_->GetFavicon(node);
     if (!favicon.IsEmpty())
-      button->SetIcon(*favicon.ToImageSkia());
+      button->SetImage(views::Button::STATE_NORMAL, *favicon.ToImageSkia());
     else
-      button->SetIcon(GetDefaultFavicon());
+      button->SetImage(views::Button::STATE_NORMAL, GetDefaultFavicon());
   }
-  button->set_max_width(kMaxButtonWidth);
+  button->SetMaxSize(gfx::Size(kMaxButtonWidth, 0));
 }
 
 void BookmarkBarView::BookmarkNodeAddedImpl(BookmarkModel* model,
                                             const BookmarkNode* parent,
                                             int index) {
-  UpdateOtherBookmarksVisibility();
-  if (parent != model_->bookmark_bar_node()) {
+  UpdateButtonsVisibility();
+  if (parent != model->bookmark_bar_node()) {
     // We only care about nodes on the bookmark bar.
     return;
   }
@@ -1431,13 +1554,13 @@ void BookmarkBarView::BookmarkNodeAddedImpl(BookmarkModel* model,
 void BookmarkBarView::BookmarkNodeRemovedImpl(BookmarkModel* model,
                                               const BookmarkNode* parent,
                                               int index) {
-  UpdateOtherBookmarksVisibility();
+  UpdateButtonsVisibility();
 
   StopThrobbing(true);
   // No need to start throbbing again as the bookmark bubble can't be up at
   // the same time as the user reorders.
 
-  if (parent != model_->bookmark_bar_node()) {
+  if (parent != model->bookmark_bar_node()) {
     // We only care about nodes on the bookmark bar.
     return;
   }
@@ -1451,13 +1574,21 @@ void BookmarkBarView::BookmarkNodeRemovedImpl(BookmarkModel* model,
 
 void BookmarkBarView::BookmarkNodeChangedImpl(BookmarkModel* model,
                                               const BookmarkNode* node) {
-  if (node->parent() != model_->bookmark_bar_node()) {
+  if (node == client_->managed_node()) {
+    // The managed node may have its title updated.
+    managed_bookmarks_button_->SetAccessibleName(
+        client_->managed_node()->GetTitle());
+    managed_bookmarks_button_->SetText(client_->managed_node()->GetTitle());
+    return;
+  }
+
+  if (node->parent() != model->bookmark_bar_node()) {
     // We only care about nodes on the bookmark bar.
     return;
   }
-  int index = model_->bookmark_bar_node()->GetIndexOf(node);
+  int index = model->bookmark_bar_node()->GetIndexOf(node);
   DCHECK_NE(-1, index);
-  views::TextButton* button = GetBookmarkButton(index);
+  views::LabelButton* button = GetBookmarkButton(index);
   gfx::Size old_pref = button->GetPreferredSize();
   ConfigureButton(node, button);
   gfx::Size new_pref = button->GetPreferredSize();
@@ -1487,10 +1618,10 @@ void BookmarkBarView::ShowDropFolderForNode(const BookmarkNode* node) {
     start_index = GetFirstHiddenNodeIndex();
 
   drop_info_->is_menu_showing = true;
-  bookmark_drop_menu_ = new BookmarkMenuController(browser_,
-      page_navigator_, GetWidget(), node, start_index);
+  bookmark_drop_menu_ = new BookmarkMenuController(
+      browser_, page_navigator_, GetWidget(), node, start_index, true);
   bookmark_drop_menu_->set_observer(this);
-  bookmark_drop_menu_->RunMenuAt(this, true);
+  bookmark_drop_menu_->RunMenuAt(this);
 }
 
 void BookmarkBarView::StopShowFolderDropMenuTimer() {
@@ -1541,7 +1672,8 @@ void BookmarkBarView::CalculateDropLocation(const DropTargetEvent& event,
   } else if (!GetBookmarkButtonCount()) {
     // No bookmarks, accept the drop.
     location->index = 0;
-    int ops = data.GetFirstNode(model_, profile->GetPath()) ?
+    const BookmarkNode* node = data.GetFirstNode(model_, profile->GetPath());
+    int ops = node && client_->CanBeEditedByUser(node) ?
         ui::DragDropTypes::DRAG_MOVE :
         ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK;
     location->operation = chrome::GetPreferredBookmarkDropOperation(
@@ -1551,7 +1683,7 @@ void BookmarkBarView::CalculateDropLocation(const DropTargetEvent& event,
 
   for (int i = 0; i < GetBookmarkButtonCount() &&
        GetBookmarkButton(i)->visible() && !found; i++) {
-    views::TextButton* button = GetBookmarkButton(i);
+    views::LabelButton* button = GetBookmarkButton(i);
     int button_x = mirrored_x - button->x();
     int button_w = button->width();
     if (button_x < button_w) {
@@ -1647,6 +1779,8 @@ void BookmarkBarView::StartThrobbing(const BookmarkNode* node,
     } else if (!overflow_only) {
       throbbing_view_ = static_cast<CustomButton*>(child_at(index));
     }
+  } else if (client_->IsDescendantOfManagedNode(node)) {
+    throbbing_view_ = managed_bookmarks_button_;
   } else if (!overflow_only) {
     throbbing_view_ = other_bookmarked_button_;
   }
@@ -1677,6 +1811,8 @@ views::CustomButton* BookmarkBarView::DetermineViewToThrobFromRemove(
     }
     return static_cast<CustomButton*>(child_at(old_index_on_bb));
   }
+  if (client_->IsDescendantOfManagedNode(parent))
+    return managed_bookmarks_button_;
   // Node wasn't on the bookmark bar, use the other bookmark button.
   return other_bookmarked_button_;
 }
@@ -1686,23 +1822,35 @@ void BookmarkBarView::UpdateColors() {
   const ui::ThemeProvider* theme_provider = GetThemeProvider();
   if (!theme_provider)
     return;
-  SkColor text_color =
+  SkColor color =
       theme_provider->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
   for (int i = 0; i < GetBookmarkButtonCount(); ++i)
-    GetBookmarkButton(i)->SetEnabledColor(text_color);
-  other_bookmarked_button()->SetEnabledColor(text_color);
+    GetBookmarkButton(i)->SetTextColor(views::Button::STATE_NORMAL, color);
+  other_bookmarked_button_->SetTextColor(views::Button::STATE_NORMAL, color);
+  managed_bookmarks_button_->SetTextColor(views::Button::STATE_NORMAL, color);
   if (apps_page_shortcut_->visible())
-    apps_page_shortcut_->SetEnabledColor(text_color);
+    apps_page_shortcut_->SetTextColor(views::Button::STATE_NORMAL, color);
 }
 
-void BookmarkBarView::UpdateOtherBookmarksVisibility() {
+void BookmarkBarView::UpdateButtonsVisibility() {
   bool has_other_children = !model_->other_node()->empty();
-  if (has_other_children == other_bookmarked_button_->visible())
-    return;
-  other_bookmarked_button_->SetVisible(has_other_children);
-  UpdateBookmarksSeparatorVisibility();
-  Layout();
-  SchedulePaint();
+  bool update_other = has_other_children != other_bookmarked_button_->visible();
+  if (update_other) {
+    other_bookmarked_button_->SetVisible(has_other_children);
+    UpdateBookmarksSeparatorVisibility();
+  }
+
+  bool show_managed = !client_->managed_node()->empty() &&
+                      browser_->profile()->GetPrefs()->GetBoolean(
+                          bookmarks::prefs::kShowManagedBookmarksInBookmarkBar);
+  bool update_managed = show_managed != managed_bookmarks_button_->visible();
+  if (update_managed)
+    managed_bookmarks_button_->SetVisible(show_managed);
+
+  if (update_other || update_managed) {
+    Layout();
+    SchedulePaint();
+  }
 }
 
 void BookmarkBarView::UpdateBookmarksSeparatorVisibility() {
@@ -1713,10 +1861,9 @@ void BookmarkBarView::UpdateBookmarksSeparatorVisibility() {
       other_bookmarked_button_->visible());
 }
 
-gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
-  gfx::Size prefsize;
-  if (!parent() && !compute_bounds_only)
-    return prefsize;
+void BookmarkBarView::LayoutItems() {
+  if (!parent())
+    return;
 
   int x = kLeftMargin;
   int top_margin = IsDetached() ? kDetachedTopMargin : 0;
@@ -1752,40 +1899,42 @@ gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
     max_x -= other_bookmarked_pref.width() + kButtonPadding;
 
   // Next, layout out the buttons. Any buttons that are placed beyond the
-  // visible region and made invisible.
+  // visible region are made invisible.
 
   // Start with the apps page shortcut button.
   if (apps_page_shortcut_->visible()) {
-    if (!compute_bounds_only) {
-      apps_page_shortcut_->SetBounds(x, y, apps_page_shortcut_pref.width(),
-                                     height);
-    }
+    apps_page_shortcut_->SetBounds(x, y, apps_page_shortcut_pref.width(),
+                                   height);
     x += apps_page_shortcut_pref.width() + kButtonPadding;
   }
 
+  // Then comes the managed bookmarks folder, if visible.
+  if (managed_bookmarks_button_->visible()) {
+    gfx::Size managed_bookmarks_pref = managed_bookmarks_button_->visible() ?
+        managed_bookmarks_button_->GetPreferredSize() : gfx::Size();
+    managed_bookmarks_button_->SetBounds(x, y, managed_bookmarks_pref.width(),
+                                         height);
+    x += managed_bookmarks_pref.width() + kButtonPadding;
+  }
+
   // Then go through the bookmark buttons.
   if (GetBookmarkButtonCount() == 0 && model_ && model_->loaded()) {
     gfx::Size pref = instructions_->GetPreferredSize();
-    if (!compute_bounds_only) {
-      instructions_->SetBounds(
-          x + kInstructionsPadding, y,
-          std::min(static_cast<int>(pref.width()),
-          max_x - x),
-          height);
-      instructions_->SetVisible(true);
-    }
+    instructions_->SetBounds(
+        x + kInstructionsPadding, y,
+        std::min(static_cast<int>(pref.width()),
+                 max_x - x),
+        height);
+    instructions_->SetVisible(true);
   } else {
-    if (!compute_bounds_only)
-      instructions_->SetVisible(false);
+    instructions_->SetVisible(false);
 
     for (int i = 0; i < GetBookmarkButtonCount(); ++i) {
       views::View* child = child_at(i);
       gfx::Size pref = child->GetPreferredSize();
       int next_x = x + pref.width() + kButtonPadding;
-      if (!compute_bounds_only) {
-        child->SetVisible(next_x < max_x);
-        child->SetBounds(x, y, pref.width(), height);
-      }
+      child->SetVisible(next_x < max_x);
+      child->SetBounds(x, y, pref.width(), height);
       x = next_x;
     }
   }
@@ -1795,58 +1944,30 @@ gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
                             child_at(GetBookmarkButtonCount() - 1)->visible());
 
   // Layout the right side buttons.
-  if (!compute_bounds_only)
-    x = max_x + kButtonPadding;
-  else
-    x += kButtonPadding;
+  x = max_x + kButtonPadding;
 
   // The overflow button.
-  if (!compute_bounds_only) {
-    overflow_button_->SetBounds(x, y, overflow_pref.width(), height);
-    overflow_button_->SetVisible(!all_visible);
-  }
+  overflow_button_->SetBounds(x, y, overflow_pref.width(), height);
+  overflow_button_->SetVisible(!all_visible);
   x += overflow_pref.width();
 
   // Separator.
   if (bookmarks_separator_view_->visible()) {
-    if (!compute_bounds_only) {
-      bookmarks_separator_view_->SetBounds(x,
-                                           y - top_margin,
-                                           bookmarks_separator_pref.width(),
-                                           height + top_margin + kBottomMargin -
-                                           separator_margin);
-    }
+    bookmarks_separator_view_->SetBounds(x,
+                                         y - top_margin,
+                                         bookmarks_separator_pref.width(),
+                                         height + top_margin + kBottomMargin -
+                                         separator_margin);
 
     x += bookmarks_separator_pref.width();
   }
 
   // The other bookmarks button.
   if (other_bookmarked_button_->visible()) {
-    if (!compute_bounds_only) {
-      other_bookmarked_button_->SetBounds(x, y, other_bookmarked_pref.width(),
-                                          height);
-    }
+    other_bookmarked_button_->SetBounds(x, y, other_bookmarked_pref.width(),
+                                        height);
     x += other_bookmarked_pref.width() + kButtonPadding;
   }
-
-  // Set the preferred size computed so far.
-  if (compute_bounds_only) {
-    x += kRightMargin;
-    prefsize.set_width(x);
-    if (IsDetached()) {
-      x += static_cast<int>(kNewtabHorizontalPadding *
-          (1 - size_animation_->GetCurrentValue()));
-      prefsize.set_height(
-          chrome::kBookmarkBarHeight +
-          static_cast<int>(
-              (chrome::kNTPBookmarkBarHeight - chrome::kBookmarkBarHeight) *
-              (1 - size_animation_->GetCurrentValue())));
-    } else {
-      prefsize.set_height(static_cast<int>(chrome::kBookmarkBarHeight *
-                                           size_animation_->GetCurrentValue()));
-    }
-  }
-  return prefsize;
 }
 
 void BookmarkBarView::OnAppsPageShortcutVisibilityPrefChanged() {