Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / frame / browser_root_view.cc
blob13125e58f45635cd21557e0a28b6db604000df07
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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/frame/browser_root_view.h"
7 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
8 #include "chrome/browser/defaults.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser_commands.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/browser/ui/views/frame/browser_frame.h"
13 #include "chrome/browser/ui/views/frame/browser_view.h"
14 #include "chrome/browser/ui/views/tabs/tab_strip.h"
15 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
16 #include "components/metrics/proto/omnibox_event.pb.h"
17 #include "components/omnibox/browser/autocomplete_classifier.h"
18 #include "components/omnibox/browser/autocomplete_match.h"
19 #include "ui/base/dragdrop/drag_drop_types.h"
20 #include "ui/base/dragdrop/os_exchange_data.h"
21 #include "ui/base/hit_test.h"
23 // static
24 const char BrowserRootView::kViewClassName[] =
25 "browser/ui/views/frame/BrowserRootView";
27 BrowserRootView::BrowserRootView(BrowserView* browser_view,
28 views::Widget* widget)
29 : views::internal::RootView(widget),
30 browser_view_(browser_view),
31 forwarding_to_tab_strip_(false) { }
33 bool BrowserRootView::GetDropFormats(
34 int* formats,
35 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
36 if (tabstrip() && tabstrip()->visible()) {
37 *formats = ui::OSExchangeData::URL | ui::OSExchangeData::STRING;
38 return true;
40 return false;
43 bool BrowserRootView::AreDropTypesRequired() {
44 return true;
47 bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) {
48 if (!tabstrip() || !tabstrip()->visible())
49 return false;
51 // If there is a URL, we'll allow the drop.
52 if (data.HasURL(ui::OSExchangeData::CONVERT_FILENAMES))
53 return true;
55 // If there isn't a URL, see if we can 'paste and go'.
56 return GetPasteAndGoURL(data, nullptr);
59 void BrowserRootView::OnDragEntered(const ui::DropTargetEvent& event) {
60 if (ShouldForwardToTabStrip(event)) {
61 forwarding_to_tab_strip_ = true;
62 scoped_ptr<ui::DropTargetEvent> mapped_event(
63 MapEventToTabStrip(event, event.data()));
64 tabstrip()->OnDragEntered(*mapped_event.get());
68 int BrowserRootView::OnDragUpdated(const ui::DropTargetEvent& event) {
69 if (ShouldForwardToTabStrip(event)) {
70 scoped_ptr<ui::DropTargetEvent> mapped_event(
71 MapEventToTabStrip(event, event.data()));
72 if (!forwarding_to_tab_strip_) {
73 tabstrip()->OnDragEntered(*mapped_event.get());
74 forwarding_to_tab_strip_ = true;
76 return tabstrip()->OnDragUpdated(*mapped_event.get());
77 } else if (forwarding_to_tab_strip_) {
78 forwarding_to_tab_strip_ = false;
79 tabstrip()->OnDragExited();
81 return ui::DragDropTypes::DRAG_NONE;
84 void BrowserRootView::OnDragExited() {
85 if (forwarding_to_tab_strip_) {
86 forwarding_to_tab_strip_ = false;
87 tabstrip()->OnDragExited();
91 int BrowserRootView::OnPerformDrop(const ui::DropTargetEvent& event) {
92 if (!forwarding_to_tab_strip_)
93 return ui::DragDropTypes::DRAG_NONE;
95 // Extract the URL and create a new ui::OSExchangeData containing the URL. We
96 // do this as the TabStrip doesn't know about the autocomplete edit and needs
97 // to know about it to handle 'paste and go'.
98 GURL url;
99 base::string16 title;
100 ui::OSExchangeData mapped_data;
101 if (!event.data().GetURLAndTitle(
102 ui::OSExchangeData::CONVERT_FILENAMES, &url, &title) ||
103 !url.is_valid()) {
104 // The url isn't valid. Use the paste and go url.
105 if (GetPasteAndGoURL(event.data(), &url))
106 mapped_data.SetURL(url, base::string16());
107 // else case: couldn't extract a url or 'paste and go' url. This ends up
108 // passing through an ui::OSExchangeData with nothing in it. We need to do
109 // this so that the tab strip cleans up properly.
110 } else {
111 mapped_data.SetURL(url, base::string16());
113 forwarding_to_tab_strip_ = false;
114 scoped_ptr<ui::DropTargetEvent> mapped_event(
115 MapEventToTabStrip(event, mapped_data));
116 return tabstrip()->OnPerformDrop(*mapped_event);
119 const char* BrowserRootView::GetClassName() const {
120 return kViewClassName;
123 bool BrowserRootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
124 if (browser_defaults::kScrollEventChangesTab) {
125 // Switch to the left/right tab if the wheel-scroll happens over the
126 // tabstrip, or the empty space beside the tabstrip.
127 views::View* hit_view = GetEventHandlerForPoint(event.location());
128 int hittest =
129 GetWidget()->non_client_view()->NonClientHitTest(event.location());
130 if (tabstrip()->Contains(hit_view) ||
131 hittest == HTCAPTION ||
132 hittest == HTTOP) {
133 int scroll_offset = abs(event.y_offset()) > abs(event.x_offset()) ?
134 event.y_offset() : event.x_offset();
135 Browser* browser = browser_view_->browser();
136 TabStripModel* model = browser->tab_strip_model();
137 // Switch to the next tab only if not at the end of the tab-strip.
138 if (scroll_offset < 0 && model->active_index() + 1 < model->count()) {
139 chrome::SelectNextTab(browser);
140 return true;
143 // Switch to the previous tab only if not at the beginning of the
144 // tab-strip.
145 if (scroll_offset > 0 && model->active_index() > 0) {
146 chrome::SelectPreviousTab(browser);
147 return true;
151 return RootView::OnMouseWheel(event);
154 void BrowserRootView::OnEventProcessingStarted(ui::Event* event) {
155 if (event->IsGestureEvent()) {
156 ui::GestureEvent* gesture_event = event->AsGestureEvent();
157 if (gesture_event->type() == ui::ET_GESTURE_TAP &&
158 gesture_event->location().y() <= 0 &&
159 gesture_event->location().x() <= browser_view_->GetBounds().width()) {
160 TouchUMA::RecordGestureAction(TouchUMA::GESTURE_ROOTVIEWTOP_TAP);
164 RootView::OnEventProcessingStarted(event);
167 bool BrowserRootView::ShouldForwardToTabStrip(
168 const ui::DropTargetEvent& event) {
169 if (!tabstrip()->visible())
170 return false;
172 // Allow the drop as long as the mouse is over the tabstrip or vertically
173 // before it.
174 gfx::Point tab_loc_in_host;
175 ConvertPointToTarget(tabstrip(), this, &tab_loc_in_host);
176 return event.y() < tab_loc_in_host.y() + tabstrip()->height();
179 ui::DropTargetEvent* BrowserRootView::MapEventToTabStrip(
180 const ui::DropTargetEvent& event,
181 const ui::OSExchangeData& data) {
182 gfx::Point tab_strip_loc(event.location());
183 ConvertPointToTarget(this, tabstrip(), &tab_strip_loc);
184 return new ui::DropTargetEvent(data, tab_strip_loc, tab_strip_loc,
185 event.source_operations());
188 TabStrip* BrowserRootView::tabstrip() const {
189 return browser_view_->tabstrip();
192 bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData& data,
193 GURL* url) {
194 if (!data.HasString())
195 return false;
197 base::string16 text;
198 if (!data.GetString(&text) || text.empty())
199 return false;
200 text = AutocompleteMatch::SanitizeString(text);
202 AutocompleteMatch match;
203 AutocompleteClassifierFactory::GetForProfile(
204 browser_view_->browser()->profile())->Classify(
205 text, false, false, metrics::OmniboxEventProto::INVALID_SPEC, &match,
206 nullptr);
207 if (!match.destination_url.is_valid())
208 return false;
210 if (url)
211 *url = match.destination_url;
212 return true;