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.h"
8 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
9 #include "chrome/browser/autocomplete/autocomplete_match.h"
10 #include "chrome/browser/defaults.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser_commands.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/browser/ui/views/frame/browser_frame.h"
15 #include "chrome/browser/ui/views/frame/browser_view.h"
16 #include "chrome/browser/ui/views/tabs/tab_strip.h"
17 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
18 #include "ui/base/dragdrop/drag_drop_types.h"
19 #include "ui/base/dragdrop/os_exchange_data.h"
22 const char BrowserRootView::kViewClassName
[] =
23 "browser/ui/views/frame/BrowserRootView";
25 BrowserRootView::BrowserRootView(BrowserView
* browser_view
,
26 views::Widget
* widget
)
27 : views::internal::RootView(widget
),
28 browser_view_(browser_view
),
29 forwarding_to_tab_strip_(false) { }
31 bool BrowserRootView::GetDropFormats(
33 std::set
<ui::OSExchangeData::CustomFormat
>* custom_formats
) {
34 if (tabstrip() && tabstrip()->visible()) {
35 *formats
= ui::OSExchangeData::URL
| ui::OSExchangeData::STRING
;
41 bool BrowserRootView::AreDropTypesRequired() {
45 bool BrowserRootView::CanDrop(const ui::OSExchangeData
& data
) {
46 if (!tabstrip() || !tabstrip()->visible())
49 // If there is a URL, we'll allow the drop.
53 // If there isn't a URL, see if we can 'paste and go'.
54 return GetPasteAndGoURL(data
, NULL
);
57 void BrowserRootView::OnDragEntered(const ui::DropTargetEvent
& event
) {
58 if (ShouldForwardToTabStrip(event
)) {
59 forwarding_to_tab_strip_
= true;
60 scoped_ptr
<ui::DropTargetEvent
> mapped_event(
61 MapEventToTabStrip(event
, event
.data()));
62 tabstrip()->OnDragEntered(*mapped_event
.get());
66 int BrowserRootView::OnDragUpdated(const ui::DropTargetEvent
& event
) {
67 if (ShouldForwardToTabStrip(event
)) {
68 scoped_ptr
<ui::DropTargetEvent
> mapped_event(
69 MapEventToTabStrip(event
, event
.data()));
70 if (!forwarding_to_tab_strip_
) {
71 tabstrip()->OnDragEntered(*mapped_event
.get());
72 forwarding_to_tab_strip_
= true;
74 return tabstrip()->OnDragUpdated(*mapped_event
.get());
75 } else if (forwarding_to_tab_strip_
) {
76 forwarding_to_tab_strip_
= false;
77 tabstrip()->OnDragExited();
79 return ui::DragDropTypes::DRAG_NONE
;
82 void BrowserRootView::OnDragExited() {
83 if (forwarding_to_tab_strip_
) {
84 forwarding_to_tab_strip_
= false;
85 tabstrip()->OnDragExited();
89 int BrowserRootView::OnPerformDrop(const ui::DropTargetEvent
& event
) {
90 if (!forwarding_to_tab_strip_
)
91 return ui::DragDropTypes::DRAG_NONE
;
93 // Extract the URL and create a new ui::OSExchangeData containing the URL. We
94 // do this as the TabStrip doesn't know about the autocomplete edit and needs
95 // to know about it to handle 'paste and go'.
98 ui::OSExchangeData mapped_data
;
99 if (!event
.data().GetURLAndTitle(
100 ui::OSExchangeData::CONVERT_FILENAMES
, &url
, &title
) ||
102 // The url isn't valid. Use the paste and go url.
103 if (GetPasteAndGoURL(event
.data(), &url
))
104 mapped_data
.SetURL(url
, base::string16());
105 // else case: couldn't extract a url or 'paste and go' url. This ends up
106 // passing through an ui::OSExchangeData with nothing in it. We need to do
107 // this so that the tab strip cleans up properly.
109 mapped_data
.SetURL(url
, base::string16());
111 forwarding_to_tab_strip_
= false;
112 scoped_ptr
<ui::DropTargetEvent
> mapped_event(
113 MapEventToTabStrip(event
, mapped_data
));
114 return tabstrip()->OnPerformDrop(*mapped_event
);
117 const char* BrowserRootView::GetClassName() const {
118 return kViewClassName
;
121 bool BrowserRootView::OnMouseWheel(const ui::MouseWheelEvent
& event
) {
122 if (browser_defaults::kScrollEventChangesTab
) {
123 // Switch to the left/right tab if the wheel-scroll happens over the
124 // tabstrip, or the empty space beside the tabstrip.
125 views::View
* hit_view
= GetEventHandlerForPoint(event
.location());
126 views::NonClientView
* non_client
= GetWidget()->non_client_view();
127 if (tabstrip()->Contains(hit_view
) ||
128 hit_view
== non_client
->frame_view()) {
129 int scroll_offset
= abs(event
.y_offset()) > abs(event
.x_offset()) ?
130 event
.y_offset() : -event
.x_offset();
131 Browser
* browser
= browser_view_
->browser();
132 TabStripModel
* model
= browser
->tab_strip_model();
133 // Switch to the next tab only if not at the end of the tab-strip.
134 if (scroll_offset
< 0 && model
->active_index() + 1 < model
->count()) {
135 chrome::SelectNextTab(browser
);
139 // Switch to the previous tab only if not at the beginning of the
141 if (scroll_offset
> 0 && model
->active_index() > 0) {
142 chrome::SelectPreviousTab(browser
);
147 return RootView::OnMouseWheel(event
);
150 void BrowserRootView::DispatchGestureEvent(ui::GestureEvent
* event
) {
151 if (event
->type() == ui::ET_GESTURE_TAP
&&
152 event
->location().y() <= 0 &&
153 event
->location().x() <= browser_view_
->GetBounds().width()) {
154 TouchUMA::RecordGestureAction(TouchUMA::GESTURE_ROOTVIEWTOP_TAP
);
157 RootView::DispatchGestureEvent(event
);
160 bool BrowserRootView::ShouldForwardToTabStrip(
161 const ui::DropTargetEvent
& event
) {
162 if (!tabstrip()->visible())
165 // Allow the drop as long as the mouse is over the tabstrip or vertically
167 gfx::Point tab_loc_in_host
;
168 ConvertPointToTarget(tabstrip(), this, &tab_loc_in_host
);
169 return event
.y() < tab_loc_in_host
.y() + tabstrip()->height();
172 ui::DropTargetEvent
* BrowserRootView::MapEventToTabStrip(
173 const ui::DropTargetEvent
& event
,
174 const ui::OSExchangeData
& data
) {
175 gfx::Point
tab_strip_loc(event
.location());
176 ConvertPointToTarget(this, tabstrip(), &tab_strip_loc
);
177 return new ui::DropTargetEvent(data
, tab_strip_loc
, tab_strip_loc
,
178 event
.source_operations());
181 TabStrip
* BrowserRootView::tabstrip() const {
182 return browser_view_
->tabstrip();
185 bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData
& data
,
187 if (!data
.HasString())
191 if (!data
.GetString(&text
) || text
.empty())
193 text
= AutocompleteMatch::SanitizeString(text
);
195 AutocompleteMatch match
;
196 AutocompleteClassifierFactory::GetForProfile(
197 browser_view_
->browser()->profile())->Classify(text
, false, false, &match
,
199 if (!match
.destination_url
.is_valid())
203 *url
= match
.destination_url
;