• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/ui/views/frame/browser_root_view.h"
6 
7 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
8 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
9 #include "chrome/browser/defaults.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/browser_commands.h"
12 #include "chrome/browser/ui/tabs/tab_strip_model.h"
13 #include "chrome/browser/ui/views/frame/browser_frame.h"
14 #include "chrome/browser/ui/views/frame/browser_view.h"
15 #include "chrome/browser/ui/views/tabs/tab_strip.h"
16 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
17 #include "components/metrics/proto/omnibox_event.pb.h"
18 #include "components/omnibox/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"
22 
23 // static
24 const char BrowserRootView::kViewClassName[] =
25     "browser/ui/views/frame/BrowserRootView";
26 
BrowserRootView(BrowserView * browser_view,views::Widget * widget)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) { }
32 
GetDropFormats(int * formats,std::set<ui::OSExchangeData::CustomFormat> * custom_formats)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;
39   }
40   return false;
41 }
42 
AreDropTypesRequired()43 bool BrowserRootView::AreDropTypesRequired() {
44   return true;
45 }
46 
CanDrop(const ui::OSExchangeData & data)47 bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) {
48   if (!tabstrip() || !tabstrip()->visible())
49     return false;
50 
51   // If there is a URL, we'll allow the drop.
52   if (data.HasURL(ui::OSExchangeData::CONVERT_FILENAMES))
53     return true;
54 
55   // If there isn't a URL, see if we can 'paste and go'.
56   return GetPasteAndGoURL(data, NULL);
57 }
58 
OnDragEntered(const ui::DropTargetEvent & event)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());
65   }
66 }
67 
OnDragUpdated(const ui::DropTargetEvent & event)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;
75     }
76     return tabstrip()->OnDragUpdated(*mapped_event.get());
77   } else if (forwarding_to_tab_strip_) {
78     forwarding_to_tab_strip_ = false;
79     tabstrip()->OnDragExited();
80   }
81   return ui::DragDropTypes::DRAG_NONE;
82 }
83 
OnDragExited()84 void BrowserRootView::OnDragExited() {
85   if (forwarding_to_tab_strip_) {
86     forwarding_to_tab_strip_ = false;
87     tabstrip()->OnDragExited();
88   }
89 }
90 
OnPerformDrop(const ui::DropTargetEvent & event)91 int BrowserRootView::OnPerformDrop(const ui::DropTargetEvent& event) {
92   if (!forwarding_to_tab_strip_)
93     return ui::DragDropTypes::DRAG_NONE;
94 
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());
112   }
113   forwarding_to_tab_strip_ = false;
114   scoped_ptr<ui::DropTargetEvent> mapped_event(
115       MapEventToTabStrip(event, mapped_data));
116   return tabstrip()->OnPerformDrop(*mapped_event);
117 }
118 
GetClassName() const119 const char* BrowserRootView::GetClassName() const {
120   return kViewClassName;
121 }
122 
OnMouseWheel(const ui::MouseWheelEvent & event)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;
141       }
142 
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;
148       }
149     }
150   }
151   return RootView::OnMouseWheel(event);
152 }
153 
OnEventFromSource(ui::Event * event)154 ui::EventDispatchDetails BrowserRootView::OnEventFromSource(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);
161     }
162   }
163 
164   return RootView::OnEventFromSource(event);
165 }
166 
ShouldForwardToTabStrip(const ui::DropTargetEvent & event)167 bool BrowserRootView::ShouldForwardToTabStrip(
168     const ui::DropTargetEvent& event) {
169   if (!tabstrip()->visible())
170     return false;
171 
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();
177 }
178 
MapEventToTabStrip(const ui::DropTargetEvent & event,const ui::OSExchangeData & data)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());
186 }
187 
tabstrip() const188 TabStrip* BrowserRootView::tabstrip() const {
189   return browser_view_->tabstrip();
190 }
191 
GetPasteAndGoURL(const ui::OSExchangeData & data,GURL * url)192 bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData& data,
193                                        GURL* url) {
194   if (!data.HasString())
195     return false;
196 
197   base::string16 text;
198   if (!data.GetString(&text) || text.empty())
199     return false;
200   text = AutocompleteMatch::SanitizeString(text);
201 
202   AutocompleteMatch match;
203   AutocompleteClassifierFactory::GetForProfile(
204       browser_view_->browser()->profile())->Classify(
205           text, false, false, metrics::OmniboxEventProto::INVALID_SPEC, &match,
206           NULL);
207   if (!match.destination_url.is_valid())
208     return false;
209 
210   if (url)
211     *url = match.destination_url;
212   return true;
213 }
214