| OLD | NEW | 
|    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h" |    5 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h" | 
|    6  |    6  | 
|    7 #include <utility> |  | 
|    8  |  | 
|    9 #include "base/macros.h" |  | 
|   10 #include "base/metrics/user_metrics.h" |    7 #include "base/metrics/user_metrics.h" | 
|   11 #include "base/strings/string16.h" |  | 
|   12 #include "base/strings/string_util.h" |    8 #include "base/strings/string_util.h" | 
|   13 #include "base/strings/utf_string_conversions.h" |    9 #include "base/strings/utf_string_conversions.h" | 
|   14 #include "chrome/app/chrome_command_ids.h" |  | 
|   15 #include "chrome/browser/bookmarks/bookmark_model_factory.h" |   10 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 
|   16 #include "chrome/browser/platform_util.h" |   11 #include "chrome/browser/platform_util.h" | 
|   17 #include "chrome/browser/profiles/profile.h" |   12 #include "chrome/browser/profiles/profile.h" | 
|   18 #include "chrome/browser/ui/bookmarks/bookmark_bubble_observer.h" |   13 #include "chrome/browser/ui/bookmarks/bookmark_bubble_observer.h" | 
|   19 #include "chrome/browser/ui/bookmarks/bookmark_editor.h" |   14 #include "chrome/browser/ui/bookmarks/bookmark_editor.h" | 
|   20 #include "chrome/browser/ui/browser_dialogs.h" |   15 #include "chrome/browser/ui/browser_dialogs.h" | 
|   21 #include "chrome/browser/ui/sync/sync_promo_ui.h" |   16 #include "chrome/browser/ui/sync/sync_promo_ui.h" | 
|   22 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h" |   17 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h" | 
|   23 #include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h" |   18 #include "chrome/browser/ui/views/sync/bubble_sync_promo_view.h" | 
|   24 #include "chrome/grit/chromium_strings.h" |   19 #include "chrome/grit/chromium_strings.h" | 
|   25 #include "chrome/grit/generated_resources.h" |   20 #include "chrome/grit/generated_resources.h" | 
|   26 #include "components/bookmarks/browser/bookmark_model.h" |   21 #include "components/bookmarks/browser/bookmark_model.h" | 
|   27 #include "components/bookmarks/browser/bookmark_utils.h" |   22 #include "components/bookmarks/browser/bookmark_utils.h" | 
|   28 #include "components/strings/grit/components_strings.h" |   23 #include "components/strings/grit/components_strings.h" | 
|   29 #include "ui/accessibility/ax_node_data.h" |   24 #include "ui/accessibility/ax_node_data.h" | 
|   30 #include "ui/base/l10n/l10n_util.h" |   25 #include "ui/base/l10n/l10n_util.h" | 
|   31 #include "ui/events/keycodes/keyboard_codes.h" |   26 #include "ui/events/keycodes/keyboard_codes.h" | 
|   32 #include "ui/views/bubble/bubble_frame_view.h" |  | 
|   33 #include "ui/views/controls/button/md_text_button.h" |   27 #include "ui/views/controls/button/md_text_button.h" | 
|   34 #include "ui/views/controls/combobox/combobox.h" |   28 #include "ui/views/controls/combobox/combobox.h" | 
|   35 #include "ui/views/controls/label.h" |   29 #include "ui/views/controls/label.h" | 
|   36 #include "ui/views/controls/link.h" |  | 
|   37 #include "ui/views/controls/textfield/textfield.h" |   30 #include "ui/views/controls/textfield/textfield.h" | 
|   38 #include "ui/views/layout/fill_layout.h" |   31 #include "ui/views/layout/fill_layout.h" | 
|   39 #include "ui/views/layout/grid_layout.h" |   32 #include "ui/views/layout/grid_layout.h" | 
|   40 #include "ui/views/widget/widget.h" |   33 #include "ui/views/widget/widget.h" | 
|   41  |   34  | 
|   42 #if defined(OS_WIN) |   35 #if defined(OS_WIN) | 
|   43 #include "chrome/browser/sync/profile_sync_service_factory.h" |   36 #include "chrome/browser/sync/profile_sync_service_factory.h" | 
|   44 #include "chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bu
     bble_view.h" |   37 #include "chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_bu
     bble_view.h" | 
|   45 #include "chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_fo
     otnote_view.h" |   38 #include "chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_fo
     otnote_view.h" | 
|   46 #include "components/browser_sync/profile_sync_service.h" |   39 #include "components/browser_sync/profile_sync_service.h" | 
|   47 #endif |   40 #endif | 
|   48  |   41  | 
|   49 using base::UserMetricsAction; |   42 using base::UserMetricsAction; | 
|   50 using bookmarks::BookmarkModel; |   43 using bookmarks::BookmarkModel; | 
|   51 using bookmarks::BookmarkNode; |   44 using bookmarks::BookmarkNode; | 
|   52 using views::ColumnSet; |   45 using views::ColumnSet; | 
|   53 using views::GridLayout; |   46 using views::GridLayout; | 
|   54  |   47  | 
|   55 namespace { |   48 namespace { | 
|   56  |   49  | 
|   57 // This combobox prevents any lengthy content from stretching the bubble view. |   50 // This combobox prevents any lengthy content from stretching the bubble view. | 
|   58 class UnsizedCombobox : public views::Combobox { |   51 class UnsizedCombobox : public views::Combobox { | 
|   59  public: |   52  public: | 
|   60   explicit UnsizedCombobox(ui::ComboboxModel* model) : views::Combobox(model) {} |   53   explicit UnsizedCombobox(ui::ComboboxModel* model) : views::Combobox(model) {} | 
|   61   ~UnsizedCombobox() override {} |   54   ~UnsizedCombobox() override {} | 
|   62  |   55  | 
 |   56   // views::Combobox: | 
|   63   gfx::Size GetPreferredSize() const override { |   57   gfx::Size GetPreferredSize() const override { | 
|   64     return gfx::Size(0, views::Combobox::GetPreferredSize().height()); |   58     return gfx::Size(0, views::Combobox::GetPreferredSize().height()); | 
|   65   } |   59   } | 
|   66  |   60  | 
|   67  private: |   61  private: | 
|   68   DISALLOW_COPY_AND_ASSIGN(UnsizedCombobox); |   62   DISALLOW_COPY_AND_ASSIGN(UnsizedCombobox); | 
|   69 }; |   63 }; | 
|   70  |   64  | 
|   71 }  // namespace |   65 }  // namespace | 
|   72  |   66  | 
|   73 BookmarkBubbleView* BookmarkBubbleView::bookmark_bubble_ = NULL; |   67 BookmarkBubbleView* BookmarkBubbleView::bookmark_bubble_ = nullptr; | 
|   74  |   68  | 
|   75 // static |   69 // static | 
|   76 views::Widget* BookmarkBubbleView::ShowBubble( |   70 views::Widget* BookmarkBubbleView::ShowBubble( | 
|   77     views::View* anchor_view, |   71     views::View* anchor_view, | 
|   78     const gfx::Rect& anchor_rect, |   72     const gfx::Rect& anchor_rect, | 
|   79     gfx::NativeView parent_window, |   73     gfx::NativeView parent_window, | 
|   80     bookmarks::BookmarkBubbleObserver* observer, |   74     bookmarks::BookmarkBubbleObserver* observer, | 
|   81     std::unique_ptr<BubbleSyncPromoDelegate> delegate, |   75     std::unique_ptr<BubbleSyncPromoDelegate> delegate, | 
|   82     Profile* profile, |   76     Profile* profile, | 
|   83     const GURL& url, |   77     const GURL& url, | 
|   84     bool already_bookmarked) { |   78     bool already_bookmarked) { | 
|   85   if (bookmark_bubble_) |   79   if (bookmark_bubble_) | 
|   86     return nullptr; |   80     return nullptr; | 
|   87  |   81  | 
|   88   bookmark_bubble_ = |   82   bookmark_bubble_ = | 
|   89       new BookmarkBubbleView(anchor_view, observer, std::move(delegate), |   83       new BookmarkBubbleView(anchor_view, observer, std::move(delegate), | 
|   90                              profile, url, !already_bookmarked); |   84                              profile, url, !already_bookmarked); | 
|   91   // Bookmark bubble should always anchor TOP_RIGHT, but the |   85   // Bookmark bubble should always anchor TOP_RIGHT, but the | 
|   92   // LocationBarBubbleDelegateView does not know that and may use different |   86   // LocationBarBubbleDelegateView does not know that and may use different | 
|   93   // arrow anchoring. |   87   // arrow anchoring. | 
|   94   bookmark_bubble_->set_arrow(views::BubbleBorder::TOP_RIGHT); |   88   bookmark_bubble_->set_arrow(views::BubbleBorder::TOP_RIGHT); | 
|   95   if (!anchor_view) { |   89   if (!anchor_view) { | 
|   96     bookmark_bubble_->SetAnchorRect(anchor_rect); |   90     bookmark_bubble_->SetAnchorRect(anchor_rect); | 
|   97     bookmark_bubble_->set_parent_window(parent_window); |   91     bookmark_bubble_->set_parent_window(parent_window); | 
|   98   } |   92   } | 
|   99   views::Widget* bubble_widget = |   93   views::Widget* bubble_widget = | 
|  100       views::BubbleDialogDelegateView::CreateBubble(bookmark_bubble_); |   94       views::BubbleDialogDelegateView::CreateBubble(bookmark_bubble_); | 
|  101   bubble_widget->Show(); |   95   bubble_widget->Show(); | 
|  102   // Select the entire title textfield contents when the bubble is first shown. |   96   // Select the entire title textfield contents when the bubble is first shown. | 
|  103   bookmark_bubble_->title_tf_->SelectAll(true); |   97   bookmark_bubble_->name_field_->SelectAll(true); | 
|  104   bookmark_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT); |   98   bookmark_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT); | 
|  105  |   99  | 
|  106   if (bookmark_bubble_->observer_) { |  100   if (bookmark_bubble_->observer_) { | 
|  107     BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile); |  101     BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile); | 
|  108     const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(url); |  102     const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(url); | 
|  109     bookmark_bubble_->observer_->OnBookmarkBubbleShown(node); |  103     bookmark_bubble_->observer_->OnBookmarkBubbleShown(node); | 
|  110   } |  104   } | 
|  111   return bubble_widget; |  105   return bubble_widget; | 
|  112 } |  106 } | 
|  113  |  107  | 
 |  108 // static | 
|  114 void BookmarkBubbleView::Hide() { |  109 void BookmarkBubbleView::Hide() { | 
|  115   if (bookmark_bubble_) |  110   if (bookmark_bubble_) | 
|  116     bookmark_bubble_->GetWidget()->Close(); |  111     bookmark_bubble_->GetWidget()->Close(); | 
|  117 } |  112 } | 
|  118  |  113  | 
|  119 BookmarkBubbleView::~BookmarkBubbleView() { |  114 BookmarkBubbleView::~BookmarkBubbleView() { | 
|  120   if (apply_edits_) { |  115   if (apply_edits_) { | 
|  121     ApplyEdits(); |  116     ApplyEdits(); | 
|  122   } else if (remove_bookmark_) { |  117   } else if (remove_bookmark_) { | 
|  123     BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile_); |  118     BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile_); | 
|  124     const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(url_); |  119     const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(url_); | 
|  125     if (node) |  120     if (node) | 
|  126       model->Remove(node); |  121       model->Remove(node); | 
|  127   } |  122   } | 
|  128   // |parent_combobox_| needs to be destroyed before |parent_model_| as it |  123   // |parent_combobox_| needs to be destroyed before |parent_model_| as it | 
|  129   // uses |parent_model_| in its destructor. |  124   // uses |parent_model_| in its destructor. | 
|  130   delete parent_combobox_; |  125   delete parent_combobox_; | 
|  131 } |  126 } | 
|  132  |  127  | 
|  133 void BookmarkBubbleView::WindowClosing() { |  128 // Private methods ------------------------------------------------------------- | 
|  134   // We have to reset |bubble_| here, not in our destructor, because we'll be |  | 
|  135   // destroyed asynchronously and the shown state will be checked before then. |  | 
|  136   DCHECK_EQ(bookmark_bubble_, this); |  | 
|  137   bookmark_bubble_ = NULL; |  | 
|  138   is_showing_ios_promotion_ = false; |  | 
|  139  |  | 
|  140   if (observer_) |  | 
|  141     observer_->OnBookmarkBubbleHidden(); |  | 
|  142 } |  | 
|  143  |  | 
|  144 bool BookmarkBubbleView::AcceleratorPressed( |  | 
|  145     const ui::Accelerator& accelerator) { |  | 
|  146   ui::KeyboardCode key_code = accelerator.key_code(); |  | 
|  147   if (key_code == ui::VKEY_RETURN) { |  | 
|  148     HandleButtonPressed(close_button_); |  | 
|  149     return true; |  | 
|  150   } |  | 
|  151   if (key_code == ui::VKEY_E && accelerator.IsAltDown()) { |  | 
|  152     HandleButtonPressed(edit_button_); |  | 
|  153     return true; |  | 
|  154   } |  | 
|  155   if (key_code == ui::VKEY_R && accelerator.IsAltDown()) { |  | 
|  156     HandleButtonPressed(remove_button_); |  | 
|  157     return true; |  | 
|  158   } |  | 
|  159  |  | 
|  160   return LocationBarBubbleDelegateView::AcceleratorPressed(accelerator); |  | 
|  161 } |  | 
|  162  |  | 
|  163 void BookmarkBubbleView::Init() { |  | 
|  164   remove_button_ = views::MdTextButton::CreateSecondaryUiButton( |  | 
|  165       this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK)); |  | 
|  166  |  | 
|  167   edit_button_ = views::MdTextButton::CreateSecondaryUiButton( |  | 
|  168       this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_OPTIONS)); |  | 
|  169  |  | 
|  170   close_button_ = views::MdTextButton::CreateSecondaryUiButton( |  | 
|  171       this, l10n_util::GetStringUTF16(IDS_DONE)); |  | 
|  172   close_button_->SetIsDefault(true); |  | 
|  173  |  | 
|  174   views::Label* combobox_label = new views::Label( |  | 
|  175       l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_FOLDER_TEXT)); |  | 
|  176  |  | 
|  177   parent_combobox_ = new UnsizedCombobox(&parent_model_); |  | 
|  178   parent_combobox_->set_listener(this); |  | 
|  179   parent_combobox_->SetAccessibleName( |  | 
|  180       l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_FOLDER_TEXT)); |  | 
|  181  |  | 
|  182   SetLayoutManager(new views::FillLayout); |  | 
|  183   bookmark_details_view_ = base::MakeUnique<View>(); |  | 
|  184   GridLayout* layout = new GridLayout(bookmark_details_view_.get()); |  | 
|  185   bookmark_details_view_->SetLayoutManager(layout); |  | 
|  186  |  | 
|  187   // This column set is used for the labels and textfields as well as the |  | 
|  188   // buttons at the bottom. |  | 
|  189   const int cs_id = 0; |  | 
|  190   ColumnSet* cs = layout->AddColumnSet(cs_id); |  | 
|  191   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); |  | 
|  192  |  | 
|  193   cs->AddColumn(provider->GetControlLabelGridAlignment(), GridLayout::CENTER, 0, |  | 
|  194                 GridLayout::USE_PREF, 0, 0); |  | 
|  195   cs->AddPaddingColumn( |  | 
|  196       0, provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL)); |  | 
|  197  |  | 
|  198   cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, |  | 
|  199                 GridLayout::USE_PREF, 0, 0); |  | 
|  200   cs->AddPaddingColumn(1, provider->GetDistanceMetric( |  | 
|  201                               DISTANCE_UNRELATED_CONTROL_HORIZONTAL_LARGE)); |  | 
|  202  |  | 
|  203   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0, |  | 
|  204                 GridLayout::USE_PREF, 0, 0); |  | 
|  205   cs->AddPaddingColumn(0, provider->GetDistanceMetric( |  | 
|  206                               views::DISTANCE_RELATED_BUTTON_HORIZONTAL)); |  | 
|  207   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0, |  | 
|  208                 GridLayout::USE_PREF, 0, 0); |  | 
|  209  |  | 
|  210   layout->StartRow(0, cs_id); |  | 
|  211   views::Label* label = new views::Label( |  | 
|  212       l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_TITLE_TEXT)); |  | 
|  213   layout->AddView(label); |  | 
|  214   title_tf_ = new views::Textfield(); |  | 
|  215   title_tf_->SetText(GetTitle()); |  | 
|  216   title_tf_->SetAccessibleName( |  | 
|  217       l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_TITLE_TEXT)); |  | 
|  218  |  | 
|  219   layout->AddView(title_tf_, 5, 1); |  | 
|  220  |  | 
|  221   layout->AddPaddingRow( |  | 
|  222       0, provider->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS).top()); |  | 
|  223  |  | 
|  224   layout->StartRow(0, cs_id); |  | 
|  225   layout->AddView(combobox_label); |  | 
|  226   layout->AddView(parent_combobox_, 5, 1); |  | 
|  227  |  | 
|  228   layout->AddPaddingRow( |  | 
|  229       0, provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)); |  | 
|  230  |  | 
|  231   layout->StartRow(0, cs_id); |  | 
|  232   layout->SkipColumns(2); |  | 
|  233   layout->AddView(remove_button_); |  | 
|  234   layout->AddView(edit_button_); |  | 
|  235   layout->AddView(close_button_); |  | 
|  236  |  | 
|  237   AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)); |  | 
|  238   AddAccelerator(ui::Accelerator(ui::VKEY_E, ui::EF_ALT_DOWN)); |  | 
|  239   AddAccelerator(ui::Accelerator(ui::VKEY_R, ui::EF_ALT_DOWN)); |  | 
|  240  |  | 
|  241   AddChildView(bookmark_details_view_.get()); |  | 
|  242 } |  | 
|  243  |  | 
|  244 gfx::ImageSkia BookmarkBubbleView::GetWindowIcon() { |  | 
|  245 #if defined(OS_WIN) |  | 
|  246   if (is_showing_ios_promotion_) { |  | 
|  247     return desktop_ios_promotion::GetPromoImage( |  | 
|  248         GetNativeTheme()->GetSystemColor( |  | 
|  249             ui::NativeTheme::kColorId_TextfieldDefaultColor)); |  | 
|  250   } |  | 
|  251 #endif |  | 
|  252   return gfx::ImageSkia(); |  | 
|  253 } |  | 
|  254  |  | 
|  255 bool BookmarkBubbleView::ShouldShowWindowIcon() const { |  | 
|  256   return is_showing_ios_promotion_; |  | 
|  257 } |  | 
|  258  |  | 
|  259 base::string16 BookmarkBubbleView::GetWindowTitle() const { |  | 
|  260 #if defined(OS_WIN) |  | 
|  261   if (is_showing_ios_promotion_) { |  | 
|  262     return desktop_ios_promotion::GetPromoTitle( |  | 
|  263         desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE); |  | 
|  264   } |  | 
|  265 #endif |  | 
|  266   return l10n_util::GetStringUTF16(newly_bookmarked_ |  | 
|  267                                        ? IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED |  | 
|  268                                        : IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK); |  | 
|  269 } |  | 
|  270  |  | 
|  271 const char* BookmarkBubbleView::GetClassName() const { |  | 
|  272   return "BookmarkBubbleView"; |  | 
|  273 } |  | 
|  274  |  | 
|  275 views::View* BookmarkBubbleView::GetInitiallyFocusedView() { |  | 
|  276   return title_tf_; |  | 
|  277 } |  | 
|  278  |  | 
|  279 views::View* BookmarkBubbleView::CreateFootnoteView() { |  | 
|  280 #if defined(OS_WIN) |  | 
|  281   if (!is_showing_ios_promotion_ && |  | 
|  282       IsIOSPromotionEligible( |  | 
|  283           desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_FOOTNOTE)) { |  | 
|  284     footnote_view_ = new DesktopIOSPromotionFootnoteView(profile_, this); |  | 
|  285     return footnote_view_; |  | 
|  286   } |  | 
|  287 #endif |  | 
|  288   if (!SyncPromoUI::ShouldShowSyncPromo(profile_)) |  | 
|  289     return nullptr; |  | 
|  290  |  | 
|  291   base::RecordAction( |  | 
|  292       base::UserMetricsAction("Signin_Impression_FromBookmarkBubble")); |  | 
|  293  |  | 
|  294   footnote_view_ = |  | 
|  295       new BubbleSyncPromoView(delegate_.get(), IDS_BOOKMARK_SYNC_PROMO_LINK, |  | 
|  296                               IDS_BOOKMARK_SYNC_PROMO_MESSAGE); |  | 
|  297   return footnote_view_; |  | 
|  298 } |  | 
|  299  |  129  | 
|  300 BookmarkBubbleView::BookmarkBubbleView( |  130 BookmarkBubbleView::BookmarkBubbleView( | 
|  301     views::View* anchor_view, |  131     views::View* anchor_view, | 
|  302     bookmarks::BookmarkBubbleObserver* observer, |  132     bookmarks::BookmarkBubbleObserver* observer, | 
|  303     std::unique_ptr<BubbleSyncPromoDelegate> delegate, |  133     std::unique_ptr<BubbleSyncPromoDelegate> delegate, | 
|  304     Profile* profile, |  134     Profile* profile, | 
|  305     const GURL& url, |  135     const GURL& url, | 
|  306     bool newly_bookmarked) |  136     bool newly_bookmarked) | 
|  307     : LocationBarBubbleDelegateView(anchor_view, nullptr), |  137     : LocationBarBubbleDelegateView(anchor_view, nullptr), | 
|  308       observer_(observer), |  138       observer_(observer), | 
|  309       delegate_(std::move(delegate)), |  139       delegate_(std::move(delegate)), | 
|  310       profile_(profile), |  140       profile_(profile), | 
|  311       url_(url), |  141       url_(url), | 
|  312       newly_bookmarked_(newly_bookmarked), |  142       newly_bookmarked_(newly_bookmarked), | 
|  313       parent_model_(BookmarkModelFactory::GetForBrowserContext(profile_), |  143       parent_model_(BookmarkModelFactory::GetForBrowserContext(profile_), | 
|  314                     BookmarkModelFactory::GetForBrowserContext(profile_) |  144                     BookmarkModelFactory::GetForBrowserContext(profile_) | 
|  315                         ->GetMostRecentlyAddedUserNodeForURL(url)), |  145                         ->GetMostRecentlyAddedUserNodeForURL(url)), | 
|  316       remove_button_(nullptr), |  146       remove_button_(nullptr), | 
|  317       edit_button_(nullptr), |  147       edit_button_(nullptr), | 
|  318       close_button_(nullptr), |  148       save_button_(nullptr), | 
|  319       title_tf_(nullptr), |  149       name_field_(nullptr), | 
|  320       parent_combobox_(nullptr), |  150       parent_combobox_(nullptr), | 
|  321       ios_promo_view_(nullptr), |  151       ios_promo_view_(nullptr), | 
|  322       footnote_view_(nullptr), |  152       footnote_view_(nullptr), | 
|  323       remove_bookmark_(false), |  153       remove_bookmark_(false), | 
|  324       apply_edits_(true), |  154       apply_edits_(true), | 
|  325       is_showing_ios_promotion_(false) { |  155       is_showing_ios_promotion_(false) { | 
|  326   chrome::RecordDialogCreation(chrome::DialogIdentifier::BOOKMARK); |  156   chrome::RecordDialogCreation(chrome::DialogIdentifier::BOOKMARK); | 
|  327 } |  157 } | 
|  328  |  158  | 
|  329 base::string16 BookmarkBubbleView::GetTitle() { |  159 base::string16 BookmarkBubbleView::GetBookmarkName() { | 
|  330   BookmarkModel* bookmark_model = |  160   BookmarkModel* bookmark_model = | 
|  331       BookmarkModelFactory::GetForBrowserContext(profile_); |  161       BookmarkModelFactory::GetForBrowserContext(profile_); | 
|  332   const BookmarkNode* node = |  162   const BookmarkNode* node = | 
|  333       bookmark_model->GetMostRecentlyAddedUserNodeForURL(url_); |  163       bookmark_model->GetMostRecentlyAddedUserNodeForURL(url_); | 
|  334   if (node) |  164   if (node) | 
|  335     return node->GetTitle(); |  165     return node->GetTitle(); | 
|  336   else |  166   else | 
|  337     NOTREACHED(); |  167     NOTREACHED(); | 
|  338   return base::string16(); |  168   return base::string16(); | 
|  339 } |  169 } | 
|  340  |  170  | 
|  341 void BookmarkBubbleView::GetAccessibleNodeData(ui::AXNodeData* node_data) { |  | 
|  342   LocationBarBubbleDelegateView::GetAccessibleNodeData(node_data); |  | 
|  343   node_data->SetName(l10n_util::GetStringUTF8( |  | 
|  344       newly_bookmarked_ ? IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED |  | 
|  345                         : IDS_BOOKMARK_AX_BUBBLE_PAGE_BOOKMARK)); |  | 
|  346 } |  | 
|  347  |  | 
|  348 void BookmarkBubbleView::ButtonPressed(views::Button* sender, |  | 
|  349                                        const ui::Event& event) { |  | 
|  350   HandleButtonPressed(sender); |  | 
|  351 } |  | 
|  352  |  | 
|  353 void BookmarkBubbleView::OnPerformAction(views::Combobox* combobox) { |  | 
|  354   if (combobox->selected_index() + 1 == parent_model_.GetItemCount()) { |  | 
|  355     base::RecordAction(UserMetricsAction("BookmarkBubble_EditFromCombobox")); |  | 
|  356     ShowEditor(); |  | 
|  357   } |  | 
|  358 } |  | 
|  359  |  | 
|  360 void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) { |  171 void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) { | 
|  361   if (sender == remove_button_) { |  172   if (sender == remove_button_) { | 
|  362     base::RecordAction(UserMetricsAction("BookmarkBubble_Unstar")); |  173     base::RecordAction(UserMetricsAction("BookmarkBubble_Unstar")); | 
|  363     // Set this so we remove the bookmark after the window closes. |  174     // Set this so we remove the bookmark after the window closes. | 
|  364     remove_bookmark_ = true; |  175     remove_bookmark_ = true; | 
|  365     apply_edits_ = false; |  176     apply_edits_ = false; | 
|  366     GetWidget()->Close(); |  177     GetWidget()->Close(); | 
|  367   } else if (sender == edit_button_) { |  178   } else if (sender == edit_button_) { | 
|  368     base::RecordAction(UserMetricsAction("BookmarkBubble_Edit")); |  179     base::RecordAction(UserMetricsAction("BookmarkBubble_Edit")); | 
|  369     ShowEditor(); |  180     ShowEditor(); | 
|  370   } else { |  181   } else { | 
|  371     DCHECK_EQ(close_button_, sender); |  182     DCHECK_EQ(save_button_, sender); | 
|  372 #if defined(OS_WIN) |  183 #if defined(OS_WIN) | 
|  373     if (IsIOSPromotionEligible( |  184     if (IsIOSPromotionEligible( | 
|  374             desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE)) { |  185             desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE)) { | 
|  375       ShowIOSPromotion( |  186       ShowIOSPromotion( | 
|  376           desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE); |  187           desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE); | 
|  377     } else { |  188     } else { | 
|  378       GetWidget()->Close(); |  189       GetWidget()->Close(); | 
|  379     } |  190     } | 
|  380 #else |  191 #else | 
|  381     GetWidget()->Close(); |  192     GetWidget()->Close(); | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|  402                          BookmarkEditor::SHOW_TREE); |  213                          BookmarkEditor::SHOW_TREE); | 
|  403 } |  214 } | 
|  404  |  215  | 
|  405 void BookmarkBubbleView::ApplyEdits() { |  216 void BookmarkBubbleView::ApplyEdits() { | 
|  406   // Set this to make sure we don't attempt to apply edits again. |  217   // Set this to make sure we don't attempt to apply edits again. | 
|  407   apply_edits_ = false; |  218   apply_edits_ = false; | 
|  408  |  219  | 
|  409   BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile_); |  220   BookmarkModel* model = BookmarkModelFactory::GetForBrowserContext(profile_); | 
|  410   const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(url_); |  221   const BookmarkNode* node = model->GetMostRecentlyAddedUserNodeForURL(url_); | 
|  411   if (node) { |  222   if (node) { | 
|  412     const base::string16 new_title = title_tf_->text(); |  223     const base::string16 new_title = name_field_->text(); | 
|  413     if (new_title != node->GetTitle()) { |  224     if (new_title != node->GetTitle()) { | 
|  414       model->SetTitle(node, new_title); |  225       model->SetTitle(node, new_title); | 
|  415       base::RecordAction( |  226       base::RecordAction( | 
|  416           UserMetricsAction("BookmarkBubble_ChangeTitleInBubble")); |  227           UserMetricsAction("BookmarkBubble_ChangeTitleInBubble")); | 
|  417     } |  228     } | 
|  418     parent_model_.MaybeChangeParent(node, parent_combobox_->selected_index()); |  229     parent_model_.MaybeChangeParent(node, parent_combobox_->selected_index()); | 
|  419   } |  230   } | 
|  420 } |  231 } | 
|  421  |  232  | 
|  422 void BookmarkBubbleView::OnIOSPromotionFootnoteLinkClicked() { |  | 
|  423 #if defined(OS_WIN) |  | 
|  424   ShowIOSPromotion( |  | 
|  425       desktop_ios_promotion::PromotionEntryPoint::FOOTNOTE_FOLLOWUP_BUBBLE); |  | 
|  426 #endif |  | 
|  427 } |  | 
|  428  |  | 
|  429 #if defined(OS_WIN) |  233 #if defined(OS_WIN) | 
|  430  |  234  | 
|  431 bool BookmarkBubbleView::IsIOSPromotionEligible( |  235 bool BookmarkBubbleView::IsIOSPromotionEligible( | 
|  432     desktop_ios_promotion::PromotionEntryPoint entry_point) { |  236     desktop_ios_promotion::PromotionEntryPoint entry_point) { | 
|  433   PrefService* prefs = profile_->GetPrefs(); |  237   PrefService* prefs = profile_->GetPrefs(); | 
|  434   const browser_sync::ProfileSyncService* sync_service = |  238   const browser_sync::ProfileSyncService* sync_service = | 
|  435       ProfileSyncServiceFactory::GetForProfile(profile_); |  239       ProfileSyncServiceFactory::GetForProfile(profile_); | 
|  436   return desktop_ios_promotion::IsEligibleForIOSPromotion(prefs, sync_service, |  240   return desktop_ios_promotion::IsEligibleForIOSPromotion(prefs, sync_service, | 
|  437                                                           entry_point); |  241                                                           entry_point); | 
|  438 } |  242 } | 
|  439  |  243  | 
|  440 void BookmarkBubbleView::ShowIOSPromotion( |  244 void BookmarkBubbleView::ShowIOSPromotion( | 
|  441     desktop_ios_promotion::PromotionEntryPoint entry_point) { |  245     desktop_ios_promotion::PromotionEntryPoint entry_point) { | 
|  442   DCHECK(!is_showing_ios_promotion_); |  246   DCHECK(!is_showing_ios_promotion_); | 
|  443   RemoveChildView(bookmark_details_view_.get()); |  247   // Hide the contents, but don't delete. It's needed in the destructor. | 
 |  248   bookmark_contents_view_->SetVisible(false); | 
|  444   delete footnote_view_; |  249   delete footnote_view_; | 
|  445   footnote_view_ = nullptr; |  250   footnote_view_ = nullptr; | 
|  446   is_showing_ios_promotion_ = true; |  251   is_showing_ios_promotion_ = true; | 
|  447   ios_promo_view_ = new DesktopIOSPromotionBubbleView(profile_, entry_point); |  252   ios_promo_view_ = new DesktopIOSPromotionBubbleView(profile_, entry_point); | 
|  448   AddChildView(ios_promo_view_); |  253   AddChildView(ios_promo_view_); | 
|  449   GetWidget()->UpdateWindowIcon(); |  254   GetWidget()->UpdateWindowIcon(); | 
|  450   GetWidget()->UpdateWindowTitle(); |  255   GetWidget()->UpdateWindowTitle(); | 
|  451   // Resize the bubble so it has the same width as the parent bubble. |  256   // Resize the bubble so it has the same width as the parent bubble. | 
|  452   ios_promo_view_->UpdateBubbleHeight(); |  257   ios_promo_view_->UpdateBubbleHeight(); | 
|  453 } |  258 } | 
|  454 #endif |  259 #endif | 
 |  260  | 
 |  261 // ui::DialogModel ------------------------------------------------------------- | 
 |  262  | 
 |  263 int BookmarkBubbleView::GetDialogButtons() const { | 
 |  264   // TODO(tapted): DialogClientView should manage the buttons. | 
 |  265   return ui::DIALOG_BUTTON_NONE; | 
 |  266 } | 
 |  267  | 
 |  268 // views::WidgetDelegate ------------------------------------------------------- | 
 |  269  | 
 |  270 views::View* BookmarkBubbleView::GetInitiallyFocusedView() { | 
 |  271   return name_field_; | 
 |  272 } | 
 |  273  | 
 |  274 base::string16 BookmarkBubbleView::GetWindowTitle() const { | 
 |  275 #if defined(OS_WIN) | 
 |  276   if (is_showing_ios_promotion_) { | 
 |  277     return desktop_ios_promotion::GetPromoTitle( | 
 |  278         desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE); | 
 |  279   } | 
 |  280 #endif | 
 |  281   return l10n_util::GetStringUTF16(newly_bookmarked_ | 
 |  282                                        ? IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED | 
 |  283                                        : IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARK); | 
 |  284 } | 
 |  285  | 
 |  286 gfx::ImageSkia BookmarkBubbleView::GetWindowIcon() { | 
 |  287 #if defined(OS_WIN) | 
 |  288   if (is_showing_ios_promotion_) { | 
 |  289     return desktop_ios_promotion::GetPromoImage( | 
 |  290         GetNativeTheme()->GetSystemColor( | 
 |  291             ui::NativeTheme::kColorId_TextfieldDefaultColor)); | 
 |  292   } | 
 |  293 #endif | 
 |  294   return gfx::ImageSkia(); | 
 |  295 } | 
 |  296  | 
 |  297 bool BookmarkBubbleView::ShouldShowWindowIcon() const { | 
 |  298   return is_showing_ios_promotion_; | 
 |  299 } | 
 |  300  | 
 |  301 void BookmarkBubbleView::WindowClosing() { | 
 |  302   // We have to reset |bubble_| here, not in our destructor, because we'll be | 
 |  303   // destroyed asynchronously and the shown state will be checked before then. | 
 |  304   DCHECK_EQ(bookmark_bubble_, this); | 
 |  305   bookmark_bubble_ = NULL; | 
 |  306   is_showing_ios_promotion_ = false; | 
 |  307  | 
 |  308   if (observer_) | 
 |  309     observer_->OnBookmarkBubbleHidden(); | 
 |  310 } | 
 |  311  | 
 |  312 // views::DialogDelegate ------------------------------------------------------- | 
 |  313  | 
 |  314 views::View* BookmarkBubbleView::CreateFootnoteView() { | 
 |  315 #if defined(OS_WIN) | 
 |  316   if (!is_showing_ios_promotion_ && | 
 |  317       IsIOSPromotionEligible( | 
 |  318           desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_FOOTNOTE)) { | 
 |  319     footnote_view_ = new DesktopIOSPromotionFootnoteView(profile_, this); | 
 |  320     return footnote_view_; | 
 |  321   } | 
 |  322 #endif | 
 |  323   if (!SyncPromoUI::ShouldShowSyncPromo(profile_)) | 
 |  324     return nullptr; | 
 |  325  | 
 |  326   base::RecordAction(UserMetricsAction("Signin_Impression_FromBookmarkBubble")); | 
 |  327  | 
 |  328   footnote_view_ = | 
 |  329       new BubbleSyncPromoView(delegate_.get(), IDS_BOOKMARK_SYNC_PROMO_LINK, | 
 |  330                               IDS_BOOKMARK_SYNC_PROMO_MESSAGE); | 
 |  331   return footnote_view_; | 
 |  332 } | 
 |  333  | 
 |  334 // views::View ----------------------------------------------------------------- | 
 |  335  | 
 |  336 const char* BookmarkBubbleView::GetClassName() const { | 
 |  337   return "BookmarkBubbleView"; | 
 |  338 } | 
 |  339  | 
 |  340 bool BookmarkBubbleView::AcceleratorPressed( | 
 |  341     const ui::Accelerator& accelerator) { | 
 |  342   ui::KeyboardCode key_code = accelerator.key_code(); | 
 |  343   if (key_code == ui::VKEY_RETURN) { | 
 |  344     HandleButtonPressed(save_button_); | 
 |  345     return true; | 
 |  346   } | 
 |  347   if (key_code == ui::VKEY_E && accelerator.IsAltDown()) { | 
 |  348     HandleButtonPressed(edit_button_); | 
 |  349     return true; | 
 |  350   } | 
 |  351   if (key_code == ui::VKEY_R && accelerator.IsAltDown()) { | 
 |  352     HandleButtonPressed(remove_button_); | 
 |  353     return true; | 
 |  354   } | 
 |  355  | 
 |  356   return LocationBarBubbleDelegateView::AcceleratorPressed(accelerator); | 
 |  357 } | 
 |  358  | 
 |  359 void BookmarkBubbleView::GetAccessibleNodeData(ui::AXNodeData* node_data) { | 
 |  360   LocationBarBubbleDelegateView::GetAccessibleNodeData(node_data); | 
 |  361   node_data->SetName(l10n_util::GetStringUTF8( | 
 |  362       newly_bookmarked_ ? IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED | 
 |  363                         : IDS_BOOKMARK_AX_BUBBLE_PAGE_BOOKMARK)); | 
 |  364 } | 
 |  365  | 
 |  366 // views::BubbleDialogDelegateView --------------------------------------------- | 
 |  367  | 
 |  368 void BookmarkBubbleView::Init() { | 
 |  369   remove_button_ = views::MdTextButton::CreateSecondaryUiButton( | 
 |  370       this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_REMOVE_BOOKMARK)); | 
 |  371  | 
 |  372   edit_button_ = views::MdTextButton::CreateSecondaryUiButton( | 
 |  373       this, l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_OPTIONS)); | 
 |  374  | 
 |  375   save_button_ = views::MdTextButton::CreateSecondaryUiButton( | 
 |  376       this, l10n_util::GetStringUTF16(IDS_DONE)); | 
 |  377   save_button_->SetIsDefault(true); | 
 |  378  | 
 |  379   views::Label* combobox_label = new views::Label( | 
 |  380       l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_FOLDER_TEXT)); | 
 |  381  | 
 |  382   parent_combobox_ = new UnsizedCombobox(&parent_model_); | 
 |  383   parent_combobox_->set_listener(this); | 
 |  384   parent_combobox_->SetAccessibleName( | 
 |  385       l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_FOLDER_TEXT)); | 
 |  386  | 
 |  387   SetLayoutManager(new views::FillLayout); | 
 |  388   bookmark_contents_view_ = new views::View(); | 
 |  389   GridLayout* layout = new GridLayout(bookmark_contents_view_); | 
 |  390   bookmark_contents_view_->SetLayoutManager(layout); | 
 |  391  | 
 |  392   // This column set is used for the labels and textfields as well as the | 
 |  393   // buttons at the bottom. | 
 |  394   const int cs_id = 0; | 
 |  395   ColumnSet* cs = layout->AddColumnSet(cs_id); | 
 |  396   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); | 
 |  397  | 
 |  398   cs->AddColumn(provider->GetControlLabelGridAlignment(), GridLayout::CENTER, 0, | 
 |  399                 GridLayout::USE_PREF, 0, 0); | 
 |  400   cs->AddPaddingColumn( | 
 |  401       0, provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL)); | 
 |  402  | 
 |  403   cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, GridLayout::USE_PREF, | 
 |  404                 0, 0); | 
 |  405   cs->AddPaddingColumn(1, provider->GetDistanceMetric( | 
 |  406                               DISTANCE_UNRELATED_CONTROL_HORIZONTAL_LARGE)); | 
 |  407  | 
 |  408   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0, | 
 |  409                 GridLayout::USE_PREF, 0, 0); | 
 |  410   cs->AddPaddingColumn(0, provider->GetDistanceMetric( | 
 |  411                               views::DISTANCE_RELATED_BUTTON_HORIZONTAL)); | 
 |  412   cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0, | 
 |  413                 GridLayout::USE_PREF, 0, 0); | 
 |  414  | 
 |  415   layout->StartRow(0, cs_id); | 
 |  416   views::Label* label = new views::Label( | 
 |  417       l10n_util::GetStringUTF16(IDS_BOOKMARK_BUBBLE_TITLE_TEXT)); | 
 |  418   layout->AddView(label); | 
 |  419   name_field_ = new views::Textfield(); | 
 |  420   name_field_->SetText(GetBookmarkName()); | 
 |  421   name_field_->SetAccessibleName( | 
 |  422       l10n_util::GetStringUTF16(IDS_BOOKMARK_AX_BUBBLE_TITLE_TEXT)); | 
 |  423  | 
 |  424   layout->AddView(name_field_, 5, 1); | 
 |  425  | 
 |  426   layout->AddPaddingRow( | 
 |  427       0, provider->GetInsetsMetric(views::INSETS_DIALOG_CONTENTS).top()); | 
 |  428  | 
 |  429   layout->StartRow(0, cs_id); | 
 |  430   layout->AddView(combobox_label); | 
 |  431   layout->AddView(parent_combobox_, 5, 1); | 
 |  432  | 
 |  433   layout->AddPaddingRow( | 
 |  434       0, provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)); | 
 |  435  | 
 |  436   layout->StartRow(0, cs_id); | 
 |  437   layout->SkipColumns(2); | 
 |  438   layout->AddView(remove_button_); | 
 |  439   layout->AddView(edit_button_); | 
 |  440   layout->AddView(save_button_); | 
 |  441  | 
 |  442   AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)); | 
 |  443   AddAccelerator(ui::Accelerator(ui::VKEY_E, ui::EF_ALT_DOWN)); | 
 |  444   AddAccelerator(ui::Accelerator(ui::VKEY_R, ui::EF_ALT_DOWN)); | 
 |  445  | 
 |  446   AddChildView(bookmark_contents_view_); | 
 |  447 } | 
 |  448  | 
 |  449 // views::ButtonListener ------------------------------------------------------- | 
 |  450  | 
 |  451 void BookmarkBubbleView::ButtonPressed(views::Button* sender, | 
 |  452                                        const ui::Event& event) { | 
 |  453   HandleButtonPressed(sender); | 
 |  454 } | 
 |  455  | 
 |  456 // views::ComboboxListener ----------------------------------------------------- | 
 |  457  | 
 |  458 void BookmarkBubbleView::OnPerformAction(views::Combobox* combobox) { | 
 |  459   if (combobox->selected_index() + 1 == parent_model_.GetItemCount()) { | 
 |  460     base::RecordAction(UserMetricsAction("BookmarkBubble_EditFromCombobox")); | 
 |  461     ShowEditor(); | 
 |  462   } | 
 |  463 } | 
 |  464  | 
 |  465 // DesktopIOSPromotionFootnoteDelegate ----------------------------------------- | 
 |  466  | 
 |  467 void BookmarkBubbleView::OnIOSPromotionFootnoteLinkClicked() { | 
 |  468 #if defined(OS_WIN) | 
 |  469   ShowIOSPromotion( | 
 |  470       desktop_ios_promotion::PromotionEntryPoint::FOOTNOTE_FOLLOWUP_BUBBLE); | 
 |  471 #endif | 
 |  472 } | 
| OLD | NEW |