browser_root_view.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/frame/immersive_mode_controller.h"
17#include "chrome/browser/ui/views/frame/top_container_view.h"
18#include "chrome/browser/ui/views/tabs/tab_strip.h"
19#include "chrome/common/chrome_notification_types.h"
20#include "grit/chromium_strings.h"
21#include "ui/base/accessibility/accessible_view_state.h"
22#include "ui/base/dragdrop/drag_drop_types.h"
23#include "ui/base/dragdrop/os_exchange_data.h"
24#include "ui/base/l10n/l10n_util.h"
25
26// static
27const char BrowserRootView::kViewClassName[] =
28    "browser/ui/views/frame/BrowserRootView";
29
30BrowserRootView::BrowserRootView(BrowserView* browser_view,
31                                 views::Widget* widget)
32    : views::internal::RootView(widget),
33      browser_view_(browser_view),
34      scheduling_immersive_reveal_painting_(false),
35      forwarding_to_tab_strip_(false) { }
36
37bool BrowserRootView::GetDropFormats(
38      int* formats,
39      std::set<ui::OSExchangeData::CustomFormat>* custom_formats) {
40  if (tabstrip() && tabstrip()->visible()) {
41    *formats = ui::OSExchangeData::URL | ui::OSExchangeData::STRING;
42    return true;
43  }
44  return false;
45}
46
47bool BrowserRootView::AreDropTypesRequired() {
48  return true;
49}
50
51bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) {
52  if (!tabstrip() || !tabstrip()->visible())
53    return false;
54
55  // If there is a URL, we'll allow the drop.
56  if (data.HasURL())
57    return true;
58
59  // If there isn't a URL, see if we can 'paste and go'.
60  return GetPasteAndGoURL(data, NULL);
61}
62
63void BrowserRootView::OnDragEntered(const ui::DropTargetEvent& event) {
64  if (ShouldForwardToTabStrip(event)) {
65    forwarding_to_tab_strip_ = true;
66    scoped_ptr<ui::DropTargetEvent> mapped_event(
67        MapEventToTabStrip(event, event.data()));
68    tabstrip()->OnDragEntered(*mapped_event.get());
69  }
70}
71
72int BrowserRootView::OnDragUpdated(const ui::DropTargetEvent& event) {
73  if (ShouldForwardToTabStrip(event)) {
74    scoped_ptr<ui::DropTargetEvent> mapped_event(
75        MapEventToTabStrip(event, event.data()));
76    if (!forwarding_to_tab_strip_) {
77      tabstrip()->OnDragEntered(*mapped_event.get());
78      forwarding_to_tab_strip_ = true;
79    }
80    return tabstrip()->OnDragUpdated(*mapped_event.get());
81  } else if (forwarding_to_tab_strip_) {
82    forwarding_to_tab_strip_ = false;
83    tabstrip()->OnDragExited();
84  }
85  return ui::DragDropTypes::DRAG_NONE;
86}
87
88void BrowserRootView::OnDragExited() {
89  if (forwarding_to_tab_strip_) {
90    forwarding_to_tab_strip_ = false;
91    tabstrip()->OnDragExited();
92  }
93}
94
95int BrowserRootView::OnPerformDrop(const ui::DropTargetEvent& event) {
96  if (!forwarding_to_tab_strip_)
97    return ui::DragDropTypes::DRAG_NONE;
98
99  // Extract the URL and create a new ui::OSExchangeData containing the URL. We
100  // do this as the TabStrip doesn't know about the autocomplete edit and needs
101  // to know about it to handle 'paste and go'.
102  GURL url;
103  string16 title;
104  ui::OSExchangeData mapped_data;
105  if (!event.data().GetURLAndTitle(&url, &title) || !url.is_valid()) {
106    // The url isn't valid. Use the paste and go url.
107    if (GetPasteAndGoURL(event.data(), &url))
108      mapped_data.SetURL(url, string16());
109    // else case: couldn't extract a url or 'paste and go' url. This ends up
110    // passing through an ui::OSExchangeData with nothing in it. We need to do
111    // this so that the tab strip cleans up properly.
112  } else {
113    mapped_data.SetURL(url, string16());
114  }
115  forwarding_to_tab_strip_ = false;
116  scoped_ptr<ui::DropTargetEvent> mapped_event(
117      MapEventToTabStrip(event, mapped_data));
118  return tabstrip()->OnPerformDrop(*mapped_event);
119}
120
121const char* BrowserRootView::GetClassName() const {
122  return kViewClassName;
123}
124
125void BrowserRootView::SchedulePaintInRect(const gfx::Rect& rect) {
126  views::internal::RootView::SchedulePaintInRect(rect);
127
128  // This function becomes reentrant when redirecting a paint-request to the
129  // reveal-view in immersive mode (because paint-requests all bubble up to the
130  // root-view). So return early in such cases.
131  if (scheduling_immersive_reveal_painting_)
132    return;
133
134  // Paint the frame caption area and window controls during immersive reveal.
135  if (browser_view_ &&
136      browser_view_->immersive_mode_controller()->IsRevealed()) {
137    base::AutoReset<bool> reset(&scheduling_immersive_reveal_painting_, true);
138    browser_view_->top_container()->SchedulePaintInRect(rect);
139  }
140}
141
142bool BrowserRootView::ShouldForwardToTabStrip(
143    const ui::DropTargetEvent& event) {
144  if (!tabstrip()->visible())
145    return false;
146
147  // Allow the drop as long as the mouse is over the tabstrip or vertically
148  // before it.
149  gfx::Point tab_loc_in_host;
150  ConvertPointToTarget(tabstrip(), this, &tab_loc_in_host);
151  return event.y() < tab_loc_in_host.y() + tabstrip()->height();
152}
153
154ui::DropTargetEvent* BrowserRootView::MapEventToTabStrip(
155    const ui::DropTargetEvent& event,
156    const ui::OSExchangeData& data) {
157  gfx::Point tab_strip_loc(event.location());
158  ConvertPointToTarget(this, tabstrip(), &tab_strip_loc);
159  return new ui::DropTargetEvent(data, tab_strip_loc, tab_strip_loc,
160                                 event.source_operations());
161}
162
163TabStrip* BrowserRootView::tabstrip() const {
164  return browser_view_->tabstrip();
165}
166
167bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData& data,
168                                       GURL* url) {
169  if (!data.HasString())
170    return false;
171
172  string16 text;
173  if (!data.GetString(&text) || text.empty())
174    return false;
175  text = AutocompleteMatch::SanitizeString(text);
176
177  AutocompleteMatch match;
178  AutocompleteClassifierFactory::GetForProfile(
179      browser_view_->browser()->profile())->Classify(text, false, false, &match,
180                                                     NULL);
181  if (!match.destination_url.is_valid())
182    return false;
183
184  if (url)
185    *url = match.destination_url;
186  return true;
187}
188