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