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