| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/views/find_bar_host.h" |
| |
| #include "app/keyboard_codes.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/find_bar_controller.h" |
| #include "chrome/browser/renderer_host/render_view_host.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/view_ids.h" |
| #include "chrome/browser/views/find_bar_view.h" |
| #include "chrome/browser/views/frame/browser_view.h" |
| #include "chrome/browser/tab_contents/tab_contents.h" |
| #include "chrome/browser/tab_contents/tab_contents_view.h" |
| #include "views/focus/external_focus_tracker.h" |
| #include "views/focus/view_storage.h" |
| #include "views/widget/root_view.h" |
| #include "views/widget/widget.h" |
| |
| namespace browser { |
| |
| // Declared in browser_dialogs.h so others don't have to depend on our header. |
| FindBar* CreateFindBar(BrowserView* browser_view) { |
| return new FindBarHost(browser_view); |
| } |
| |
| } // namespace browser |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // FindBarHost, public: |
| |
| FindBarHost::FindBarHost(BrowserView* browser_view) |
| : DropdownBarHost(browser_view), |
| find_bar_controller_(NULL) { |
| Init(new FindBarView(this)); |
| } |
| |
| FindBarHost::~FindBarHost() { |
| } |
| |
| bool FindBarHost::MaybeForwardKeystrokeToWebpage( |
| const views::Textfield::Keystroke& key_stroke) { |
| if (!ShouldForwardKeystrokeToWebpageNative(key_stroke)) { |
| // Native implementation says not to forward these events. |
| return false; |
| } |
| |
| switch (key_stroke.GetKeyboardCode()) { |
| case app::VKEY_DOWN: |
| case app::VKEY_UP: |
| case app::VKEY_PRIOR: |
| case app::VKEY_NEXT: |
| break; |
| case app::VKEY_HOME: |
| case app::VKEY_END: |
| if (key_stroke.IsControlHeld()) |
| break; |
| // Fall through. |
| default: |
| return false; |
| } |
| |
| TabContents* contents = find_bar_controller_->tab_contents(); |
| if (!contents) |
| return false; |
| |
| RenderViewHost* render_view_host = contents->render_view_host(); |
| |
| // Make sure we don't have a text field element interfering with keyboard |
| // input. Otherwise Up and Down arrow key strokes get eaten. "Nom Nom Nom". |
| render_view_host->ClearFocusedNode(); |
| NativeWebKeyboardEvent event = GetKeyboardEvent(contents, key_stroke); |
| render_view_host->ForwardKeyboardEvent(event); |
| return true; |
| } |
| |
| FindBarController* FindBarHost::GetFindBarController() const { |
| return find_bar_controller_; |
| } |
| |
| void FindBarHost::SetFindBarController(FindBarController* find_bar_controller) { |
| find_bar_controller_ = find_bar_controller; |
| } |
| |
| void FindBarHost::Show(bool animate) { |
| DropdownBarHost::Show(animate); |
| } |
| |
| void FindBarHost::Hide(bool animate) { |
| DropdownBarHost::Hide(animate); |
| } |
| |
| void FindBarHost::SetFocusAndSelection() { |
| DropdownBarHost::SetFocusAndSelection(); |
| } |
| |
| void FindBarHost::ClearResults(const FindNotificationDetails& results) { |
| find_bar_view()->UpdateForResult(results, string16()); |
| } |
| |
| void FindBarHost::StopAnimation() { |
| DropdownBarHost::StopAnimation(); |
| } |
| |
| void FindBarHost::MoveWindowIfNecessary(const gfx::Rect& selection_rect, |
| bool no_redraw) { |
| // We only move the window if one is active for the current TabContents. If we |
| // don't check this, then SetWidgetPosition below will end up making the Find |
| // Bar visible. |
| if (!find_bar_controller_->tab_contents() || |
| !find_bar_controller_->tab_contents()->find_ui_active()) { |
| return; |
| } |
| |
| gfx::Rect new_pos = GetDialogPosition(selection_rect); |
| SetDialogPosition(new_pos, no_redraw); |
| |
| // May need to redraw our frame to accommodate bookmark bar styles. |
| view()->SchedulePaint(); |
| } |
| |
| void FindBarHost::SetFindText(const string16& find_text) { |
| find_bar_view()->SetFindText(find_text); |
| } |
| |
| void FindBarHost::UpdateUIForFindResult(const FindNotificationDetails& result, |
| const string16& find_text) { |
| if (!find_text.empty()) |
| find_bar_view()->UpdateForResult(result, find_text); |
| |
| // We now need to check if the window is obscuring the search results. |
| if (!result.selection_rect().IsEmpty()) |
| MoveWindowIfNecessary(result.selection_rect(), false); |
| |
| // Once we find a match we no longer want to keep track of what had |
| // focus. EndFindSession will then set the focus to the page content. |
| if (result.number_of_matches() > 0) |
| ResetFocusTracker(); |
| } |
| |
| bool FindBarHost::IsFindBarVisible() { |
| return DropdownBarHost::IsVisible(); |
| } |
| |
| void FindBarHost::RestoreSavedFocus() { |
| if (focus_tracker() == NULL) { |
| // TODO(brettw) Focus() should be on TabContentsView. |
| find_bar_controller_->tab_contents()->Focus(); |
| } else { |
| focus_tracker()->FocusLastFocusedExternalView(); |
| } |
| } |
| |
| FindBarTesting* FindBarHost::GetFindBarTesting() { |
| return this; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // FindBarWin, views::AcceleratorTarget implementation: |
| |
| bool FindBarHost::AcceleratorPressed(const views::Accelerator& accelerator) { |
| app::KeyboardCode key = accelerator.GetKeyCode(); |
| if (key == app::VKEY_RETURN && accelerator.IsCtrlDown()) { |
| // Ctrl+Enter closes the Find session and navigates any link that is active. |
| find_bar_controller_->EndFindSession(FindBarController::kActivateSelection); |
| } else if (key == app::VKEY_ESCAPE) { |
| // This will end the Find session and hide the window, causing it to loose |
| // focus and in the process unregister us as the handler for the Escape |
| // accelerator through the FocusWillChange event. |
| find_bar_controller_->EndFindSession(FindBarController::kKeepSelection); |
| } else { |
| NOTREACHED() << "Unknown accelerator"; |
| } |
| |
| return true; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // FindBarTesting implementation: |
| |
| bool FindBarHost::GetFindBarWindowInfo(gfx::Point* position, |
| bool* fully_visible) { |
| if (!find_bar_controller_ || |
| #if defined(OS_WIN) |
| !::IsWindow(host()->GetNativeView())) { |
| #else |
| false) { |
| // TODO(sky): figure out linux side. |
| // This is tricky due to asynchronous nature of x11. |
| // See bug http://crbug.com/28629. |
| #endif |
| if (position) |
| *position = gfx::Point(); |
| if (fully_visible) |
| *fully_visible = false; |
| return false; |
| } |
| |
| gfx::Rect window_rect; |
| host()->GetBounds(&window_rect, true); |
| if (position) |
| *position = window_rect.origin(); |
| if (fully_visible) |
| *fully_visible = IsVisible() && !IsAnimating(); |
| return true; |
| } |
| |
| string16 FindBarHost::GetFindText() { |
| return find_bar_view()->GetFindText(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Overridden from DropdownBarHost: |
| |
| gfx::Rect FindBarHost::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { |
| // Find the area we have to work with (after accounting for scrollbars, etc). |
| gfx::Rect widget_bounds; |
| GetWidgetBounds(&widget_bounds); |
| if (widget_bounds.IsEmpty()) |
| return gfx::Rect(); |
| |
| // Ask the view how large an area it needs to draw on. |
| gfx::Size prefsize = view()->GetPreferredSize(); |
| |
| // Place the view in the top right corner of the widget boundaries (top left |
| // for RTL languages). |
| gfx::Rect view_location; |
| int x = widget_bounds.x(); |
| if (!base::i18n::IsRTL()) |
| x += widget_bounds.width() - prefsize.width(); |
| int y = widget_bounds.y(); |
| view_location.SetRect(x, y, prefsize.width(), prefsize.height()); |
| |
| // When we get Find results back, we specify a selection rect, which we |
| // should strive to avoid overlapping. But first, we need to offset the |
| // selection rect (if one was provided). |
| if (!avoid_overlapping_rect.IsEmpty()) { |
| // For comparison (with the Intersects function below) we need to account |
| // for the fact that we draw the Find widget relative to the Chrome frame, |
| // whereas the selection rect is relative to the page. |
| GetWidgetPositionNative(&avoid_overlapping_rect); |
| } |
| |
| gfx::Rect new_pos = FindBarController::GetLocationForFindbarView( |
| view_location, widget_bounds, avoid_overlapping_rect); |
| |
| // While we are animating, the Find window will grow bottoms up so we need to |
| // re-position the widget so that it appears to grow out of the toolbar. |
| if (animation_offset() > 0) |
| new_pos.Offset(0, std::min(0, -animation_offset())); |
| |
| return new_pos; |
| } |
| |
| void FindBarHost::SetDialogPosition(const gfx::Rect& new_pos, bool no_redraw) { |
| if (new_pos.IsEmpty()) |
| return; |
| |
| // Make sure the window edges are clipped to just the visible region. We need |
| // to do this before changing position, so that when we animate the closure |
| // of it it doesn't look like the window crumbles into the toolbar. |
| UpdateWindowEdges(new_pos); |
| |
| SetWidgetPositionNative(new_pos, no_redraw); |
| } |
| |
| void FindBarHost::GetWidgetBounds(gfx::Rect* bounds) { |
| DCHECK(bounds); |
| // The BrowserView does Layout for the components that we care about |
| // positioning relative to, so we ask it to tell us where we should go. |
| *bounds = browser_view()->GetFindBarBoundingBox(); |
| } |
| |
| void FindBarHost::RegisterAccelerators() { |
| DropdownBarHost::RegisterAccelerators(); |
| |
| // Register for Ctrl+Return. |
| views::Accelerator escape(app::VKEY_RETURN, false, true, false); |
| focus_manager()->RegisterAccelerator(escape, this); |
| } |
| |
| void FindBarHost::UnregisterAccelerators() { |
| // Unregister Ctrl+Return. |
| views::Accelerator escape(app::VKEY_RETURN, false, true, false); |
| focus_manager()->UnregisterAccelerator(escape, this); |
| |
| DropdownBarHost::UnregisterAccelerators(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // private: |
| |
| FindBarView* FindBarHost::find_bar_view() { |
| return static_cast<FindBarView*>(view()); |
| } |