Home | History | Annotate | Download | only in frame
      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