browser_root_view.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 23const char BrowserRootView::kViewClassName[] = 24 "browser/ui/views/frame/BrowserRootView"; 25 26BrowserRootView::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 32bool 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 42bool BrowserRootView::AreDropTypesRequired() { 43 return true; 44} 45 46bool 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(ui::OSExchangeData::CONVERT_FILENAMES)) 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 58void 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 67int 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 83void BrowserRootView::OnDragExited() { 84 if (forwarding_to_tab_strip_) { 85 forwarding_to_tab_strip_ = false; 86 tabstrip()->OnDragExited(); 87 } 88} 89 90int 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 118const char* BrowserRootView::GetClassName() const { 119 return kViewClassName; 120} 121 122bool 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 151void 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 161bool 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 173ui::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 182TabStrip* BrowserRootView::tabstrip() const { 183 return browser_view_->tabstrip(); 184} 185 186bool 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} 207