diff options
Diffstat (limited to 'chrome/browser/ui/views/find_bar_host.cc')
-rw-r--r-- | chrome/browser/ui/views/find_bar_host.cc | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/chrome/browser/ui/views/find_bar_host.cc b/chrome/browser/ui/views/find_bar_host.cc new file mode 100644 index 0000000..3926e70 --- /dev/null +++ b/chrome/browser/ui/views/find_bar_host.cc @@ -0,0 +1,297 @@ +// 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.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/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()); +} |