browser_root_view.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 "base/auto_reset.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/autocomplete/autocomplete_classifier.h"
10#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
11#include "chrome/browser/autocomplete/autocomplete_match.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/omnibox/location_bar.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 "chrome/common/chrome_notification_types.h"
19#include "grit/chromium_strings.h"
20#include "ui/base/accessibility/accessible_view_state.h"
21#include "ui/base/dragdrop/drag_drop_types.h"
22#include "ui/base/dragdrop/os_exchange_data.h"
23#include "ui/base/l10n/l10n_util.h"
24
25// static
26const char BrowserRootView::kViewClassName[] =
27    "browser/ui/views/frame/BrowserRootView";
28
29BrowserRootView::BrowserRootView(BrowserView* browser_view,
30                                 views::Widget* widget)
31    : views::internal::RootView(widget),
32      browser_view_(browser_view),
33      forwarding_to_tab_strip_(false) { }
34
35bool BrowserRootView::GetDropFormats(
36      int* formats,
37      std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
38  if (tabstrip() && tabstrip()->visible()) {
39    *formats = ui::OSExchangeData::URL | ui::OSExchangeData::STRING;
40    return true;
41  }
42  return false;
43}
44
45bool BrowserRootView::AreDropTypesRequired() {
46  return true;
47}
48
49bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) {
50  if (!tabstrip() || !tabstrip()->visible())
51    return false;
52
53  // If there is a URL, we'll allow the drop.
54  if (data.HasURL())
55    return true;
56
57  // If there isn't a URL, see if we can 'paste and go'.
58  return GetPasteAndGoURL(data, NULL);
59}
60
61void BrowserRootView::OnDragEntered(const ui::DropTargetEvent& event) {
62  if (ShouldForwardToTabStrip(event)) {
63    forwarding_to_tab_strip_ = true;
64    scoped_ptr<ui::DropTargetEvent> mapped_event(
65        MapEventToTabStrip(event, event.data()));
66    tabstrip()->OnDragEntered(*mapped_event.get());
67  }
68}
69
70int BrowserRootView::OnDragUpdated(const ui::DropTargetEvent& event) {
71  if (ShouldForwardToTabStrip(event)) {
72    scoped_ptr<ui::DropTargetEvent> mapped_event(
73        MapEventToTabStrip(event, event.data()));
74    if (!forwarding_to_tab_strip_) {
75      tabstrip()->OnDragEntered(*mapped_event.get());
76      forwarding_to_tab_strip_ = true;
77    }
78    return tabstrip()->OnDragUpdated(*mapped_event.get());
79  } else if (forwarding_to_tab_strip_) {
80    forwarding_to_tab_strip_ = false;
81    tabstrip()->OnDragExited();
82  }
83  return ui::DragDropTypes::DRAG_NONE;
84}
85
86void BrowserRootView::OnDragExited() {
87  if (forwarding_to_tab_strip_) {
88    forwarding_to_tab_strip_ = false;
89    tabstrip()->OnDragExited();
90  }
91}
92
93int BrowserRootView::OnPerformDrop(const ui::DropTargetEvent& event) {
94  if (!forwarding_to_tab_strip_)
95    return ui::DragDropTypes::DRAG_NONE;
96
97  // Extract the URL and create a new ui::OSExchangeData containing the URL. We
98  // do this as the TabStrip doesn't know about the autocomplete edit and needs
99  // to know about it to handle 'paste and go'.
100  GURL url;
101  string16 title;
102  ui::OSExchangeData mapped_data;
103  if (!event.data().GetURLAndTitle(&url, &title) || !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, 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, 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
119const char* BrowserRootView::GetClassName() const {
120  return kViewClassName;
121}
122
123void BrowserRootView::DispatchGestureEvent(ui::GestureEvent* event) {
124  if (event->type() == ui::ET_GESTURE_TAP &&
125      event->location().y() <= 0 &&
126      event->location().x() <= browser_view_->GetBounds().width()) {
127    TouchUMA::RecordGestureAction(TouchUMA::GESTURE_ROOTVIEWTOP_TAP);
128  }
129
130  RootView::DispatchGestureEvent(event);
131}
132
133bool BrowserRootView::ShouldForwardToTabStrip(
134    const ui::DropTargetEvent& event) {
135  if (!tabstrip()->visible())
136    return false;
137
138  // Allow the drop as long as the mouse is over the tabstrip or vertically
139  // before it.
140  gfx::Point tab_loc_in_host;
141  ConvertPointToTarget(tabstrip(), this, &tab_loc_in_host);
142  return event.y() < tab_loc_in_host.y() + tabstrip()->height();
143}
144
145ui::DropTargetEvent* BrowserRootView::MapEventToTabStrip(
146    const ui::DropTargetEvent& event,
147    const ui::OSExchangeData& data) {
148  gfx::Point tab_strip_loc(event.location());
149  ConvertPointToTarget(this, tabstrip(), &tab_strip_loc);
150  return new ui::DropTargetEvent(data, tab_strip_loc, tab_strip_loc,
151                                 event.source_operations());
152}
153
154TabStrip* BrowserRootView::tabstrip() const {
155  return browser_view_->tabstrip();
156}
157
158bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData& data,
159                                       GURL* url) {
160  if (!data.HasString())
161    return false;
162
163  string16 text;
164  if (!data.GetString(&text) || text.empty())
165    return false;
166  text = AutocompleteMatch::SanitizeString(text);
167
168  AutocompleteMatch match;
169  AutocompleteClassifierFactory::GetForProfile(
170      browser_view_->browser()->profile())->Classify(text, false, false, &match,
171                                                     NULL);
172  if (!match.destination_url.is_valid())
173    return false;
174
175  if (url)
176    *url = match.destination_url;
177  return true;
178}
179