1 // Copyright (c) 2011 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/utf_string_conversions.h" 8 #include "chrome/browser/autocomplete/autocomplete.h" 9 #include "chrome/browser/autocomplete/autocomplete_classifier.h" 10 #include "chrome/browser/autocomplete/autocomplete_match.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/ui/omnibox/location_bar.h" 13 #include "chrome/browser/ui/views/frame/browser_frame.h" 14 #include "chrome/browser/ui/views/frame/browser_view.h" 15 #include "chrome/browser/ui/views/tabs/tab_strip.h" 16 #include "grit/chromium_strings.h" 17 #include "ui/base/accessibility/accessible_view_state.h" 18 #include "ui/base/dragdrop/drag_drop_types.h" 19 #include "ui/base/dragdrop/os_exchange_data.h" 20 #include "ui/base/l10n/l10n_util.h" 21 22 BrowserRootView::BrowserRootView(BrowserView* browser_view, 23 views::Widget* widget) 24 : views::RootView(widget), 25 browser_view_(browser_view), 26 forwarding_to_tab_strip_(false) { } 27 28 bool BrowserRootView::GetDropFormats( 29 int* formats, 30 std::set<ui::OSExchangeData::CustomFormat>* custom_formats) { 31 if (tabstrip() && tabstrip()->IsVisible()) { 32 *formats = ui::OSExchangeData::URL | ui::OSExchangeData::STRING; 33 return true; 34 } 35 return false; 36 } 37 38 bool BrowserRootView::AreDropTypesRequired() { 39 return true; 40 } 41 42 bool BrowserRootView::CanDrop(const ui::OSExchangeData& data) { 43 if (!tabstrip() || !tabstrip()->IsVisible()) 44 return false; 45 46 // If there is a URL, we'll allow the drop. 47 if (data.HasURL()) 48 return true; 49 50 // If there isn't a URL, see if we can 'paste and go'. 51 return GetPasteAndGoURL(data, NULL); 52 } 53 54 void BrowserRootView::OnDragEntered(const views::DropTargetEvent& event) { 55 if (ShouldForwardToTabStrip(event)) { 56 forwarding_to_tab_strip_ = true; 57 scoped_ptr<views::DropTargetEvent> mapped_event( 58 MapEventToTabStrip(event, event.data())); 59 tabstrip()->OnDragEntered(*mapped_event.get()); 60 } 61 } 62 63 int BrowserRootView::OnDragUpdated(const views::DropTargetEvent& event) { 64 if (ShouldForwardToTabStrip(event)) { 65 scoped_ptr<views::DropTargetEvent> mapped_event( 66 MapEventToTabStrip(event, event.data())); 67 if (!forwarding_to_tab_strip_) { 68 tabstrip()->OnDragEntered(*mapped_event.get()); 69 forwarding_to_tab_strip_ = true; 70 } 71 return tabstrip()->OnDragUpdated(*mapped_event.get()); 72 } else if (forwarding_to_tab_strip_) { 73 forwarding_to_tab_strip_ = false; 74 tabstrip()->OnDragExited(); 75 } 76 return ui::DragDropTypes::DRAG_NONE; 77 } 78 79 void BrowserRootView::OnDragExited() { 80 if (forwarding_to_tab_strip_) { 81 forwarding_to_tab_strip_ = false; 82 tabstrip()->OnDragExited(); 83 } 84 } 85 86 int BrowserRootView::OnPerformDrop(const views::DropTargetEvent& event) { 87 if (!forwarding_to_tab_strip_) 88 return ui::DragDropTypes::DRAG_NONE; 89 90 // Extract the URL and create a new ui::OSExchangeData containing the URL. We 91 // do this as the TabStrip doesn't know about the autocomplete edit and needs 92 // to know about it to handle 'paste and go'. 93 GURL url; 94 string16 title; 95 ui::OSExchangeData mapped_data; 96 if (!event.data().GetURLAndTitle(&url, &title) || !url.is_valid()) { 97 // The url isn't valid. Use the paste and go url. 98 if (GetPasteAndGoURL(event.data(), &url)) 99 mapped_data.SetURL(url, string16()); 100 // else case: couldn't extract a url or 'paste and go' url. This ends up 101 // passing through an ui::OSExchangeData with nothing in it. We need to do 102 // this so that the tab strip cleans up properly. 103 } else { 104 mapped_data.SetURL(url, string16()); 105 } 106 forwarding_to_tab_strip_ = false; 107 scoped_ptr<views::DropTargetEvent> mapped_event( 108 MapEventToTabStrip(event, mapped_data)); 109 return tabstrip()->OnPerformDrop(*mapped_event); 110 } 111 112 void BrowserRootView::GetAccessibleState(ui::AccessibleViewState* state) { 113 RootView::GetAccessibleState(state); 114 state->name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME); 115 } 116 117 bool BrowserRootView::ShouldForwardToTabStrip( 118 const views::DropTargetEvent& event) { 119 if (!tabstrip()->IsVisible()) 120 return false; 121 122 // Allow the drop as long as the mouse is over the tabstrip or vertically 123 // before it. 124 gfx::Point tab_loc_in_host; 125 ConvertPointToView(tabstrip(), this, &tab_loc_in_host); 126 return event.y() < tab_loc_in_host.y() + tabstrip()->height(); 127 } 128 129 views::DropTargetEvent* BrowserRootView::MapEventToTabStrip( 130 const views::DropTargetEvent& event, 131 const ui::OSExchangeData& data) { 132 gfx::Point tab_strip_loc(event.location()); 133 ConvertPointToView(this, tabstrip(), &tab_strip_loc); 134 return new views::DropTargetEvent(data, tab_strip_loc.x(), 135 tab_strip_loc.y(), 136 event.source_operations()); 137 } 138 139 AbstractTabStripView* BrowserRootView::tabstrip() const { 140 return browser_view_->tabstrip(); 141 } 142 143 bool BrowserRootView::GetPasteAndGoURL(const ui::OSExchangeData& data, 144 GURL* url) { 145 if (!data.HasString()) 146 return false; 147 148 string16 text; 149 if (!data.GetString(&text) || text.empty()) 150 return false; 151 152 AutocompleteMatch match; 153 browser_view_->browser()->profile()->GetAutocompleteClassifier()->Classify( 154 text, string16(), false, &match, NULL); 155 if (!match.destination_url.is_valid()) 156 return false; 157 158 if (url) 159 *url = match.destination_url; 160 return true; 161 } 162