Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / frame / browser_root_view.cc
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/autocomplete/autocomplete_input.h"
10 #include "chrome/browser/autocomplete/autocomplete_match.h"
11 #include "chrome/browser/defaults.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/browser/ui/views/frame/browser_frame.h"
16 #include "chrome/browser/ui/views/frame/browser_view.h"
17 #include "chrome/browser/ui/views/tabs/tab_strip.h"
18 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
19 #include "ui/base/dragdrop/drag_drop_types.h"
20 #include "ui/base/dragdrop/os_exchange_data.h"
21
22 // static
23 const char BrowserRootView::kViewClassName[] =
24     "browser/ui/views/frame/BrowserRootView";
25
26 BrowserRootView::BrowserRootView(BrowserView* browser_view,
27                                  views::Widget* widget)
28     : views::internal::RootView(widget),
29       browser_view_(browser_view),
30       forwarding_to_tab_strip_(false) { }
31
32 bool BrowserRootView::GetDropFormats(
33       int* formats,
34       std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
35   if (tabstrip() && tabstrip()->visible()) {
36     *formats = ui::OSExchangeData::URL | ui::OSExchangeData::STRING;
37     return true;
38   }
39   return false;
40 }
41
42 bool BrowserRootView::AreDropTypesRequired() {
43   return true;
44 }
45
46 bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) {
47   if (!tabstrip() || !tabstrip()->visible())
48     return false;
49
50   // If there is a URL, we'll allow the drop.
51   if (data.HasURL())
52     return true;
53
54   // If there isn't a URL, see if we can 'paste and go'.
55   return GetPasteAndGoURL(data, NULL);
56 }
57
58 void BrowserRootView::OnDragEntered(const ui::DropTargetEvent& event) {
59   if (ShouldForwardToTabStrip(event)) {
60     forwarding_to_tab_strip_ = true;
61     scoped_ptr<ui::DropTargetEvent> mapped_event(
62         MapEventToTabStrip(event, event.data()));
63     tabstrip()->OnDragEntered(*mapped_event.get());
64   }
65 }
66
67 int BrowserRootView::OnDragUpdated(const ui::DropTargetEvent& event) {
68   if (ShouldForwardToTabStrip(event)) {
69     scoped_ptr<ui::DropTargetEvent> mapped_event(
70         MapEventToTabStrip(event, event.data()));
71     if (!forwarding_to_tab_strip_) {
72       tabstrip()->OnDragEntered(*mapped_event.get());
73       forwarding_to_tab_strip_ = true;
74     }
75     return tabstrip()->OnDragUpdated(*mapped_event.get());
76   } else if (forwarding_to_tab_strip_) {
77     forwarding_to_tab_strip_ = false;
78     tabstrip()->OnDragExited();
79   }
80   return ui::DragDropTypes::DRAG_NONE;
81 }
82
83 void BrowserRootView::OnDragExited() {
84   if (forwarding_to_tab_strip_) {
85     forwarding_to_tab_strip_ = false;
86     tabstrip()->OnDragExited();
87   }
88 }
89
90 int BrowserRootView::OnPerformDrop(const ui::DropTargetEvent& event) {
91   if (!forwarding_to_tab_strip_)
92     return ui::DragDropTypes::DRAG_NONE;
93
94   // Extract the URL and create a new ui::OSExchangeData containing the URL. We
95   // do this as the TabStrip doesn't know about the autocomplete edit and needs
96   // to know about it to handle 'paste and go'.
97   GURL url;
98   base::string16 title;
99   ui::OSExchangeData mapped_data;
100   if (!event.data().GetURLAndTitle(
101            ui::OSExchangeData::CONVERT_FILENAMES, &url, &title) ||
102       !url.is_valid()) {
103     // The url isn't valid. Use the paste and go url.
104     if (GetPasteAndGoURL(event.data(), &url))
105       mapped_data.SetURL(url, base::string16());
106     // else case: couldn't extract a url or 'paste and go' url. This ends up
107     // passing through an ui::OSExchangeData with nothing in it. We need to do
108     // this so that the tab strip cleans up properly.
109   } else {
110     mapped_data.SetURL(url, base::string16());
111   }
112   forwarding_to_tab_strip_ = false;
113   scoped_ptr<ui::DropTargetEvent> mapped_event(
114       MapEventToTabStrip(event, mapped_data));
115   return tabstrip()->OnPerformDrop(*mapped_event);
116 }
117
118 const char* BrowserRootView::GetClassName() const {
119   return kViewClassName;
120 }
121
122 bool BrowserRootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
123   if (browser_defaults::kScrollEventChangesTab) {
124     // Switch to the left/right tab if the wheel-scroll happens over the
125     // tabstrip, or the empty space beside the tabstrip.
126     views::View* hit_view = GetEventHandlerForPoint(event.location());
127     views::NonClientView* non_client = GetWidget()->non_client_view();
128     if (tabstrip()->Contains(hit_view) ||
129         hit_view == non_client->frame_view()) {
130       int scroll_offset = abs(event.y_offset()) > abs(event.x_offset()) ?
131           event.y_offset() : -event.x_offset();
132       Browser* browser = browser_view_->browser();
133       TabStripModel* model = browser->tab_strip_model();
134       // Switch to the next tab only if not at the end of the tab-strip.
135       if (scroll_offset < 0 && model->active_index() + 1 < model->count()) {
136         chrome::SelectNextTab(browser);
137         return true;
138       }
139
140       // Switch to the previous tab only if not at the beginning of the
141       // tab-strip.
142       if (scroll_offset > 0 && model->active_index() > 0) {
143         chrome::SelectPreviousTab(browser);
144         return true;
145       }
146     }
147   }
148   return RootView::OnMouseWheel(event);
149 }
150
151 void BrowserRootView::DispatchGestureEvent(ui::GestureEvent* event) {
152   if (event->type() == ui::ET_GESTURE_TAP &&
153       event->location().y() <= 0 &&
154       event->location().x() <= browser_view_->GetBounds().width()) {
155     TouchUMA::RecordGestureAction(TouchUMA::GESTURE_ROOTVIEWTOP_TAP);
156   }
157
158   RootView::DispatchGestureEvent(event);
159 }
160
161 bool BrowserRootView::ShouldForwardToTabStrip(
162     const ui::DropTargetEvent& event) {
163   if (!tabstrip()->visible())
164     return false;
165
166   // Allow the drop as long as the mouse is over the tabstrip or vertically
167   // before it.
168   gfx::Point tab_loc_in_host;
169   ConvertPointToTarget(tabstrip(), this, &tab_loc_in_host);
170   return event.y() < tab_loc_in_host.y() + tabstrip()->height();
171 }
172
173 ui::DropTargetEvent* BrowserRootView::MapEventToTabStrip(
174     const ui::DropTargetEvent& event,
175     const ui::OSExchangeData& data) {
176   gfx::Point tab_strip_loc(event.location());
177   ConvertPointToTarget(this, tabstrip(), &tab_strip_loc);
178   return new ui::DropTargetEvent(data, tab_strip_loc, tab_strip_loc,
179                                  event.source_operations());
180 }
181
182 TabStrip* BrowserRootView::tabstrip() const {
183   return browser_view_->tabstrip();
184 }
185
186 bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData& data,
187                                        GURL* url) {
188   if (!data.HasString())
189     return false;
190
191   base::string16 text;
192   if (!data.GetString(&text) || text.empty())
193     return false;
194   text = AutocompleteMatch::SanitizeString(text);
195
196   AutocompleteMatch match;
197   AutocompleteClassifierFactory::GetForProfile(
198       browser_view_->browser()->profile())->Classify(
199           text, false, false, AutocompleteInput::INVALID_SPEC, &match, NULL);
200   if (!match.destination_url.is_valid())
201     return false;
202
203   if (url)
204     *url = match.destination_url;
205   return true;
206 }