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/chrome_notification_types.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/ui/omnibox/location_bar.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 "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 26 const char BrowserRootView::kViewClassName[] = 27 "browser/ui/views/frame/BrowserRootView"; 28 29 BrowserRootView::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 35 bool 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 45 bool BrowserRootView::AreDropTypesRequired() { 46 return true; 47 } 48 49 bool 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 61 void 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 70 int 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 86 void BrowserRootView::OnDragExited() { 87 if (forwarding_to_tab_strip_) { 88 forwarding_to_tab_strip_ = false; 89 tabstrip()->OnDragExited(); 90 } 91 } 92 93 int 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 119 const char* BrowserRootView::GetClassName() const { 120 return kViewClassName; 121 } 122 123 void 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 133 bool 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 145 ui::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 154 TabStrip* BrowserRootView::tabstrip() const { 155 return browser_view_->tabstrip(); 156 } 157 158 bool 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