Chromium Code Reviews| Index: mash/browser/browser.cc |
| diff --git a/mash/browser/browser.cc b/mash/browser/browser.cc |
| index 5094674b278692b92b142b20bfdfcc038bd56f69..c3676ccc1e7e5d9ce3860d032d908a43fdbe59f0 100644 |
| --- a/mash/browser/browser.cc |
| +++ b/mash/browser/browser.cc |
| @@ -5,11 +5,13 @@ |
| #include "mash/browser/browser.h" |
| #include "base/macros.h" |
| +#include "base/memory/ptr_util.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| #include "base/timer/timer.h" |
| #include "components/mus/public/cpp/window.h" |
| #include "components/mus/public/cpp/window_tree_client.h" |
| @@ -22,12 +24,15 @@ |
| #include "services/shell/public/cpp/shell_client.h" |
| #include "services/tracing/public/cpp/tracing_impl.h" |
| #include "ui/aura/mus/mus_util.h" |
| +#include "ui/base/models/menu_model.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/paint_throbber.h" |
| #include "ui/gfx/text_constants.h" |
| #include "ui/native_theme/native_theme.h" |
| #include "ui/views/background.h" |
| #include "ui/views/controls/button/label_button.h" |
| +#include "ui/views/controls/menu/menu_model_adapter.h" |
| +#include "ui/views/controls/menu/menu_runner.h" |
| #include "ui/views/controls/textfield/textfield.h" |
| #include "ui/views/controls/textfield/textfield_controller.h" |
| #include "ui/views/mus/aura_init.h" |
| @@ -43,6 +48,175 @@ void EnableButton(views::CustomButton* button, bool enabled) { |
| : views::Button::STATE_DISABLED); |
| } |
| +struct NavEntry { |
| + NavEntry(const base::string16& title, int offset) |
| + : title(title), offset(offset) {} |
| + ~NavEntry() {} |
| + |
| + base::string16 title; |
| + int offset; |
|
sky
2016/06/08 21:31:21
What is offset? At least document it.
|
| +}; |
| + |
| +class NavMenuModel : public ui::MenuModel { |
| + public: |
| + class Delegate { |
| + public: |
| + virtual void NavigateToOffset(int offset) = 0; |
| + }; |
| + |
| + NavMenuModel(const std::vector<NavEntry>& entries, Delegate* delegate) |
| + : entries_(entries), navigation_delegate_(delegate) {} |
| + ~NavMenuModel() override {} |
| + |
| + private: |
| + bool HasIcons() const override { return false; } |
| + int GetItemCount() const override { |
| + return static_cast<int>(entries_.size()); |
| + } |
| + ui::MenuModel::ItemType GetTypeAt(int index) const override { |
| + return ui::MenuModel::TYPE_COMMAND; |
| + } |
| + ui::MenuSeparatorType GetSeparatorTypeAt(int index) const override { |
| + return ui::NORMAL_SEPARATOR; |
| + } |
| + int GetCommandIdAt(int index) const override { |
| + return index; |
| + } |
| + base::string16 GetLabelAt(int index) const override { |
| + return entries_[index].title; |
| + } |
| + base::string16 GetSublabelAt(int index) const override { |
| + return base::string16(); |
| + } |
| + base::string16 GetMinorTextAt(int index) const override { |
| + return base::string16(); |
| + } |
| + bool IsItemDynamicAt(int index) const override { return false; } |
| + bool GetAcceleratorAt(int index, |
| + ui::Accelerator* accelerator) const override { |
| + return false; |
| + } |
| + bool IsItemCheckedAt(int index) const override { return false; } |
| + int GetGroupIdAt(int index) const override { return -1; } |
| + bool GetIconAt(int index, gfx::Image* icon) override { return false; } |
| + ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override { |
| + return nullptr; |
| + } |
| + bool IsEnabledAt(int index) const override { return true; } |
| + bool IsVisibleAt(int index) const override { return true; } |
| + ui::MenuModel* GetSubmenuModelAt(int index) const override { return nullptr; } |
| + void HighlightChangedTo(int index) override {} |
| + void ActivatedAt(int index) override { |
| + ActivatedAt(index, 0); |
| + } |
| + void ActivatedAt(int index, int event_flags) override { |
| + navigation_delegate_->NavigateToOffset(entries_[index].offset); |
| + } |
| + void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) override { |
| + delegate_ = delegate; |
| + } |
| + ui::MenuModelDelegate* GetMenuModelDelegate() const override { |
| + return delegate_; |
| + } |
| + |
| + int multiplier_; |
|
sky
2016/06/08 21:31:20
remove as not used.
|
| + ui::MenuModelDelegate* delegate_ = nullptr; |
| + Delegate* navigation_delegate_; |
| + std::vector<NavEntry> entries_; |
| + int cursor_; |
|
sky
2016/06/08 21:31:20
Not used?
|
| + |
| + DISALLOW_COPY_AND_ASSIGN(NavMenuModel); |
| +}; |
| + |
| +class NavButton : public views::LabelButton { |
| + public: |
| + enum class Type { |
| + BACK, |
| + FORWARD |
| + }; |
| + |
| + class ModelProvider { |
| + public: |
| + virtual std::unique_ptr<ui::MenuModel> CreateMenuModel(Type type) = 0; |
| + }; |
| + |
| + NavButton(Type type, |
| + ModelProvider* model_provider, |
| + views::ButtonListener* listener, |
| + const base::string16& label) |
| + : views::LabelButton(listener, label), |
| + type_(type), |
| + model_provider_(model_provider), |
| + show_menu_factory_(this) {} |
| + ~NavButton() override {} |
| + |
| + private: |
| + bool OnMousePressed(const ui::MouseEvent& event) override { |
|
sky
2016/06/08 21:31:21
Prefix with // views::LabelButton: (or something s
|
| + if (IsTriggerableEvent(event) && enabled() && |
| + HitTestPoint(event.location())) { |
| + y_pos_on_lbuttondown_ = event.y(); |
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&NavButton::ShowMenu, show_menu_factory_.GetWeakPtr(), |
| + ui::GetMenuSourceTypeForEvent(event)), |
| + base::TimeDelta::FromMilliseconds(500)); |
| + } |
| + return LabelButton::OnMousePressed(event); |
| + } |
| + bool OnMouseDragged(const ui::MouseEvent& event) override { |
| + bool result = LabelButton::OnMouseDragged(event); |
| + if (show_menu_factory_.HasWeakPtrs()) { |
| + if (event.y() > y_pos_on_lbuttondown_ + GetHorizontalDragThreshold()) { |
| + show_menu_factory_.InvalidateWeakPtrs(); |
| + ShowMenu(ui::GetMenuSourceTypeForEvent(event)); |
| + } |
| + } |
| + return result; |
| + } |
| + void OnMouseReleased(const ui::MouseEvent& event) override { |
| + if (IsTriggerableEvent(event)) |
| + show_menu_factory_.InvalidateWeakPtrs(); |
| + LabelButton::OnMouseReleased(event); |
| + } |
| + |
|
sky
2016/06/08 21:31:21
nit: remove extra whitespace.
|
| + |
| + void ShowMenu(ui::MenuSourceType source_type) { |
| + gfx::Rect local = GetLocalBounds(); |
| + gfx::Point menu_position(local.origin()); |
| + menu_position.Offset(0, local.height() - 1); |
| + View::ConvertPointToScreen(this, &menu_position); |
| + |
| + model_ = std::move(model_provider_->CreateMenuModel(type_)); |
| + menu_model_adapter_.reset(new views::MenuModelAdapter( |
| + model_.get(), |
| + base::Bind(&NavButton::OnMenuClosed, base::Unretained(this)))); |
| + menu_model_adapter_->set_triggerable_event_flags(triggerable_event_flags()); |
| + menu_runner_.reset(new views::MenuRunner( |
| + menu_model_adapter_->CreateMenu(), |
| + views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::ASYNC)); |
| + ignore_result(menu_runner_->RunMenuAt( |
| + GetWidget(), nullptr, gfx::Rect(menu_position, gfx::Size(0, 0)), |
| + views::MENU_ANCHOR_TOPLEFT, source_type)); |
| + } |
| + |
| + void OnMenuClosed() { |
| + SetMouseHandler(nullptr); |
| + model_.reset(); |
| + menu_runner_.reset(); |
| + menu_model_adapter_.reset(); |
| + } |
| + |
| + Type type_; |
| + ModelProvider* model_provider_; |
| + int y_pos_on_lbuttondown_ = 0; |
| + std::unique_ptr<ui::MenuModel> model_; |
| + std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; |
| + std::unique_ptr<views::MenuRunner> menu_runner_; |
| + base::WeakPtrFactory<NavButton> show_menu_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(NavButton); |
| +}; |
| + |
| class ProgressBar : public views::View { |
| public: |
| ProgressBar() {} |
| @@ -115,7 +289,9 @@ class Throbber : public views::View { |
| class UI : public views::WidgetDelegateView, |
| public views::ButtonListener, |
| public views::TextfieldController, |
| - public navigation::mojom::ViewClient { |
| + public navigation::mojom::ViewClient, |
| + public NavButton::ModelProvider, |
| + public NavMenuModel::Delegate { |
| public: |
| enum class Type { WINDOW, POPUP }; |
| @@ -125,9 +301,10 @@ class UI : public views::WidgetDelegateView, |
| navigation::mojom::ViewClientRequest request) |
| : browser_(browser), |
| type_(type), |
| - back_button_(new views::LabelButton(this, base::ASCIIToUTF16("Back"))), |
| - forward_button_( |
| - new views::LabelButton(this, base::ASCIIToUTF16("Forward"))), |
| + back_button_(new NavButton(NavButton::Type::BACK, this, this, |
| + base::ASCIIToUTF16("Back"))), |
| + forward_button_(new NavButton(NavButton::Type::FORWARD, this, this, |
| + base::ASCIIToUTF16("Forward"))), |
| reload_button_( |
| new views::LabelButton(this, base::ASCIIToUTF16("Reload"))), |
| prompt_(new views::Textfield), |
| @@ -321,6 +498,66 @@ class UI : public views::WidgetDelegateView, |
| browser_->AddWindow(window); |
| } |
| void Close() override { GetWidget()->Close(); } |
| + void NavigationPending(navigation::mojom::NavigationEntryPtr entry) override { |
| + pending_nav_ = std::move(entry); |
| + } |
| + void NavigationCommitted( |
| + navigation::mojom::NavigationCommittedDetailsPtr details, |
| + int current_index) override { |
| + switch (details->type) { |
| + case navigation::mojom::NavigationType::NEW_PAGE: { |
| + if (navigation_list_.size() > 1) { |
| + auto it = navigation_list_.begin() + (cursor_ + 1); |
| + if (it < navigation_list_.end()) |
| + navigation_list_.erase(++it, navigation_list_.end()); |
| + } |
| + navigation_list_.push_back(std::move(pending_nav_)); |
|
sky
2016/06/08 21:31:20
Don't you want to add at current_index?
Ben Goodger (Google)
2016/06/08 21:55:03
At this point we should have trimmed the navigatio
|
| + cursor_ = current_index; |
| + break; |
| + } |
| + case navigation::mojom::NavigationType::EXISTING_PAGE: |
| + cursor_ = current_index; |
|
sky
2016/06/08 21:31:20
How come you don't replace the entry at current_in
Ben Goodger (Google)
2016/06/08 21:55:04
That appears to lose data. Sometimes the pending e
|
| + break; |
| + } |
| + } |
| + void NavigationEntryChanged(navigation::mojom::NavigationEntryPtr entry, |
| + int entry_index) override { |
| + navigation_list_[entry_index] = std::move(entry); |
| + } |
| + void NavigationListPruned(bool from_front, int count) override { |
| + DCHECK(count < static_cast<int>(navigation_list_.size())); |
| + if (from_front) { |
|
sky
2016/06/08 21:31:20
Did you mean to have !from_front here as the first
Ben Goodger (Google)
2016/06/08 21:55:04
For navigations, the list reversed. The "front" of
|
| + auto it = navigation_list_.end() - count; |
| + navigation_list_.erase(it, navigation_list_.end()); |
| + } else { |
| + auto it = navigation_list_.begin() + count; |
| + navigation_list_.erase(navigation_list_.begin(), it); |
| + } |
| + } |
| + |
| + // NavButton::ModelProvider: |
| + std::unique_ptr<ui::MenuModel> CreateMenuModel( |
| + NavButton::Type type) override { |
| + std::vector<NavEntry> entries; |
| + if (type == NavButton::Type::BACK) { |
| + for (int i = cursor_ - 1, offset = -1; i >= 0; --i, --offset) { |
| + std::string title = navigation_list_[i]->title; |
| + entries.push_back(NavEntry(base::UTF8ToUTF16(title), offset)); |
| + } |
| + } else { |
| + for (int i = cursor_ + 1, offset = 1; i < navigation_list_.size(); |
| + ++i, ++offset) { |
| + std::string title = navigation_list_[i]->title; |
| + entries.push_back(NavEntry(base::UTF8ToUTF16(title), offset)); |
| + } |
| + } |
| + return base::WrapUnique(new NavMenuModel(entries, this)); |
| + } |
| + |
| + // NavMenuModel::Delegate: |
| + void NavigateToOffset(int offset) override { |
| + view_->NavigateToOffset(offset); |
|
sky
2016/06/08 21:31:20
What happens if navigation_list_ changed while the
Ben Goodger (Google)
2016/06/08 21:55:03
These are great questions for an implementation of
|
| + } |
| void ToggleDebugView() { |
| showing_debug_view_ = !showing_debug_view_; |
| @@ -350,6 +587,10 @@ class UI : public views::WidgetDelegateView, |
| base::string16 current_title_; |
| GURL current_url_; |
| + navigation::mojom::NavigationEntryPtr pending_nav_; |
| + std::vector<navigation::mojom::NavigationEntryPtr> navigation_list_; |
| + int cursor_ = 0; |
|
sky
2016/06/08 21:31:20
Document what this is. I would be inclined to name
|
| + |
| bool showing_debug_view_ = false; |
| DISALLOW_COPY_AND_ASSIGN(UI); |