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