diff options
Diffstat (limited to 'chrome/browser/views/find_bar_win.cc')
-rw-r--r-- | chrome/browser/views/find_bar_win.cc | 427 |
1 files changed, 159 insertions, 268 deletions
diff --git a/chrome/browser/views/find_bar_win.cc b/chrome/browser/views/find_bar_win.cc index 671cc92..9ab7f1d 100644 --- a/chrome/browser/views/find_bar_win.cc +++ b/chrome/browser/views/find_bar_win.cc @@ -6,11 +6,12 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/find_notification_details.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/bookmark_bar_view.h" #include "chrome/browser/views/find_bar_view.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/browser/tab_contents/web_contents_view.h" #include "chrome/common/notification_service.h" @@ -20,25 +21,20 @@ #include "chrome/views/view_storage.h" #include "chrome/views/widget_win.h" -int FindBarWin::request_id_counter_ = 0; - // The minimum space between the FindInPage window and the search result. static const int kMinFindWndDistanceFromSelection = 5; -// The amount of space we expect the window border to take up. -static const int kWindowBorderWidth = 3; - //////////////////////////////////////////////////////////////////////////////// // FindBarWin, public: -FindBarWin::FindBarWin(WebContentsView* parent_tab, HWND parent_hwnd) - : parent_tab_(parent_tab), - current_request_id_(request_id_counter_++), - parent_hwnd_(parent_hwnd), +FindBarWin::FindBarWin(BrowserView* browser_view) + : web_contents_(NULL), + browser_view_(browser_view), find_dialog_animation_offset_(0), - show_on_tab_selection_(false), focus_manager_(NULL), old_accel_target_for_esc_(NULL) { + HWND parent_hwnd = browser_view->GetWidget()->GetHWND(); + // Start listening to focus changes, so we can register and unregister our // own handler for Escape. SetFocusChangeListener(parent_hwnd); @@ -49,36 +45,38 @@ FindBarWin::FindBarWin(WebContentsView* parent_tab, HWND parent_hwnd) view_ = new FindBarView(this); - views::FocusManager* focus_manager; - focus_manager = views::FocusManager::GetFocusManager(parent_hwnd_); + views::FocusManager* focus_manager = views::FocusManager::GetFocusManager( + parent_hwnd); DCHECK(focus_manager); // Stores the currently focused view, and tracks focus changes so that we can // restore focus when the find box is closed. focus_tracker_.reset(new views::ExternalFocusTracker(view_, focus_manager)); - // Figure out where to place the dialog, initialize and set the position. - gfx::Rect find_dlg_rect = GetDialogPosition(gfx::Rect()); + // Initialize the native window. set_window_style(WS_CHILD | WS_CLIPCHILDREN); set_window_ex_style(WS_EX_TOPMOST); - WidgetWin::Init(parent_hwnd, find_dlg_rect, false); + WidgetWin::Init(parent_hwnd, gfx::Rect(), false); SetContentsView(view_); // Start the process of animating the opening of the window. animation_.reset(new SlideAnimation(this)); - animation_->Show(); } FindBarWin::~FindBarWin() { - Close(); } // TODO(brettw) this should not be so complicated. The view should really be in // charge of these regions. CustomFrameWindow will do this for us. It will also // let us set a path for the window region which will avoid some logic here. void FindBarWin::UpdateWindowEdges(const gfx::Rect& new_pos) { - int w = new_pos.width(); - int h = new_pos.height(); + // |w| is used to make it easier to create the part of the polygon that curves + // the right side of the Find window. It essentially keeps track of the + // x-pixel position of the right-most background image inside the view. + // TODO(finnur): Let the view tell us how to draw the curves or convert + // this to a CustomFrameWindow. + int w = new_pos.width() - 6; // -6 positions us at the left edge of the + // rightmost background image of the view. // This polygon array represents the outline of the background image for the // dialog. Basically, it encompasses only the visible pixels of the @@ -150,8 +148,8 @@ void FindBarWin::UpdateWindowEdges(const gfx::Rect& new_pos) { // // TODO(brettw) this constant is evil. This is the amount of room we've added // to the window size, when we set the region, it can change the size. - static const int kAddedWidth = 14; - int difference = (curr_pos_relative_.right() - kAddedWidth) - + static const int kAddedWidth = 7; + int difference = (new_pos.right() - kAddedWidth) - dialog_bounds.width() - views::NativeScrollBar::GetVerticalScrollBarWidth() + 1; @@ -180,26 +178,14 @@ void FindBarWin::UpdateWindowEdges(const gfx::Rect& new_pos) { } void FindBarWin::Show() { - // Note: This function is called when the user presses Ctrl+F or switches back - // to the parent tab of the Find window (assuming the Find window has been - // opened at least once). If the Find window is already visible, we should - // just forward the command to the view so that it will select all text and - // grab focus. If the window is not visible, however, there are two scenarios: - if (!IsVisible() && !animation_->IsAnimating()) { - if (show_on_tab_selection_) { - // The tab just got re-selected and we need to show the window again - // (without animation). We also want to reset the window location so that - // we don't surprise the user by popping up to the left for no apparent - // reason. - gfx::Rect new_pos = GetDialogPosition(gfx::Rect()); - SetDialogPosition(new_pos); - } else { - // The Find window was dismissed and we need to start the animation again. - animation_->Show(); - } + // Only show the animation if we're not already showing a find bar for the + // selected WebContents. + if (!web_contents_->find_ui_active()) { + web_contents_->set_find_ui_active(true); + animation_->Reset(); + animation_->Show(); } - - view_->OnShow(); + view_->SetFocusAndSelection(); } bool FindBarWin::IsAnimating() { @@ -207,122 +193,115 @@ bool FindBarWin::IsAnimating() { } void FindBarWin::EndFindSession() { - if (IsVisible()) { - show_on_tab_selection_ = false; - animation_->Hide(); - - // We reset the match count here so that we don't show old results when the - // user has navigated to another page. We could alternatively achieve the - // same effect by nulling the search string, but then the user looses the - // last search that was entered, which can be frustrating if searching for - // the same string on multiple pages. - view_->ResetMatchCount(); - - // When we hide the window, we need to notify the renderer that we are done - // for now, so that we can abort the scoping effort and clear all the - // tick-marks and highlighting. - StopFinding(false); // false = don't clear selection on page. - - // When we get dismissed we restore the focus to where it belongs. - RestoreSavedFocus(); - } -} - -void FindBarWin::Close() { - // We may already have been destroyed if the selection resulted in a tab - // switch which will have reactivated the browser window and closed us, so - // we need to check to see if we're still a window before trying to destroy - // ourself. - if (IsWindow()) - DestroyWindow(); + animation_->Reset(1.0); + animation_->Hide(); + + // When we hide the window, we need to notify the renderer that we are done + // for now, so that we can abort the scoping effort and clear all the + // tickmarks and highlighting. + web_contents_->StopFinding(false); // false = don't clear selection on + // page. + view_->UpdateForResult(web_contents_->find_result(), std::wstring()); + + // When we get dismissed we restore the focus to where it belongs. + RestoreSavedFocus(); } -void FindBarWin::DidBecomeSelected() { - if (!IsVisible() && show_on_tab_selection_) { - Show(); - show_on_tab_selection_ = false; +void FindBarWin::ChangeWebContents(WebContents* contents) { + if (web_contents_) { + NotificationService::current()->RemoveObserver( + this, NotificationType::FIND_RESULT_AVAILABLE, + Source<TabContents>(web_contents_)); + NotificationService::current()->RemoveObserver( + this, NotificationType::NAV_ENTRY_COMMITTED, + Source<NavigationController>(web_contents_->controller())); + if (animation_->IsAnimating()) + animation_->End(); } -} -void FindBarWin::DidBecomeUnselected() { - if (::IsWindow(GetHWND()) && IsVisible()) { - // Finish any existing animations. - if (animation_->IsAnimating()) { - show_on_tab_selection_ = animation_->IsShowing(); - animation_->End(); - } else { - show_on_tab_selection_ = true; + web_contents_ = contents; + + if (web_contents_) { + if (IsVisible() && web_contents_ && !web_contents_->find_ui_active()) + ShowWindow(SW_HIDE); + + NotificationService::current()->AddObserver( + this, NotificationType::FIND_RESULT_AVAILABLE, + Source<TabContents>(web_contents_)); + NotificationService::current()->AddObserver( + this, NotificationType::NAV_ENTRY_COMMITTED, + Source<NavigationController>(web_contents_->controller())); + + // Update the find bar with existing results and search text, regardless of + // whether or not the find bar is visible, so that if it's subsequently + // shown it is showing the right state for this tab. We update the find text + // _first_ since the FindBarView checks its emptiness to see if it should + // clear the result count display when there's nothing in the box. + view_->SetFindText(web_contents_->find_text()); + + if (web_contents_->find_ui_active()) { + // A tab with a visible find bar just got selected and we need to show the + // find bar but without animation since it was already animated into its + // visible state. We also want to reset the window location so that + // we don't surprise the user by popping up to the left for no apparent + // reason. + gfx::Rect new_pos = GetDialogPosition(gfx::Rect()); + SetDialogPosition(new_pos, false); + + // Only modify focus and selection if Find is active, otherwise the Find + // Bar will interfere with user input. + view_->SetFocusAndSelection(); } - ShowWindow(SW_HIDE); + UpdateUIForFindResult(web_contents_->find_result(), + web_contents_->find_text()); } } -void FindBarWin::StartFinding(bool forward_direction) { - if (find_string_.empty()) +void FindBarWin::MoveWindowIfNecessary(const gfx::Rect& selection_rect, + bool no_redraw) { + // We only move the window if one is active for the current WebContents. If we + // don't check this, then SetDialogPosition below will end up making the Find + // Bar visible. + if (!web_contents_ || !web_contents_->find_ui_active()) return; - bool find_next = last_find_string_ == find_string_; - if (!find_next) - current_request_id_ = request_id_counter_++; - - last_find_string_ = find_string_; - - GetRenderViewHost()->StartFinding(current_request_id_, - find_string_, - forward_direction, - false, // case sensitive - find_next); -} - -void FindBarWin::StopFinding(bool clear_selection) { - last_find_string_.clear(); - GetRenderViewHost()->StopFinding(clear_selection); -} - -void FindBarWin::MoveWindowIfNecessary( - const gfx::Rect& selection_rect) { gfx::Rect new_pos = GetDialogPosition(selection_rect); - SetDialogPosition(new_pos); + SetDialogPosition(new_pos, no_redraw); - // May need to redraw our frame to accomodate bookmark bar - // styles. + // May need to redraw our frame to accommodate bookmark bar styles. view_->SchedulePaint(); } -void FindBarWin::RespondToResize(const gfx::Size& new_size) { - if (!IsVisible()) - return; - - // We are only interested in changes to width. - if (window_size_.width() == new_size.width()) - return; - - // Save the new size so we can compare later and ignore future invocations - // of RespondToResize. - window_size_ = new_size; - - gfx::Rect new_pos = GetDialogPosition(gfx::Rect()); - SetDialogPosition(new_pos); -} - -void FindBarWin::SetParent(HWND new_parent) { - DCHECK(new_parent); - if (parent_hwnd_ != new_parent) { - // Sync up the focus listener with the new focus manager. - SetFocusChangeListener(new_parent); - - parent_hwnd_ = new_parent; - ::SetParent(GetHWND(), new_parent); - - // The MSDN documentation specifies that you need to manually update the - // UI state after changing the parent. - ::SendMessage(new_parent, - WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0); - - // We have a new focus manager now, so start tracking with that. - focus_tracker_.reset(new views::ExternalFocusTracker(view_, - focus_manager_)); +//////////////////////////////////////////////////////////////////////////////// +// FindBarWin, NotificationObserver implementation: + +void FindBarWin::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::FIND_RESULT_AVAILABLE) { + // Don't update for notifications from TabContentses other than the one we are + // actively tracking. + if (Source<TabContents>(source).ptr() == web_contents_) { + UpdateUIForFindResult(web_contents_->find_result(), + web_contents_->find_text()); + FindNotificationDetails details = web_contents_->find_result(); + } + } else if (type == NotificationType::NAV_ENTRY_COMMITTED) { + NavigationController* source_controller = + Source<NavigationController>(source).ptr(); + if (source_controller == web_contents_->controller()) { + NavigationController::LoadCommittedDetails* commit_details = + Details<NavigationController::LoadCommittedDetails>(details).ptr(); + PageTransition::Type transition_type = + commit_details->entry->transition_type(); + // We hide the FindInPage window when the user navigates away, except on + // reload. + if (IsVisible() && PageTransition::StripQualifier(transition_type) != + PageTransition::RELOAD) { + EndFindSession(); + } + } } } @@ -330,6 +309,9 @@ void FindBarWin::SetParent(HWND new_parent) { // FindBarWin, views::WidgetWin implementation: void FindBarWin::OnFinalMessage(HWND window) { + // TODO(beng): Destroy the RootView before destroying the Focus Manager will + // allow us to remove this method. + // We are exiting, so we no longer need to monitor focus changes. focus_manager_->RemoveFocusChangeListener(this); @@ -384,14 +366,15 @@ bool FindBarWin::AcceleratorPressed(const views::Accelerator& accelerator) { void FindBarWin::AnimationProgressed(const Animation* animation) { // First, we calculate how many pixels to slide the window. + gfx::Size pref_size = view_->GetPreferredSize(); find_dialog_animation_offset_ = static_cast<int>((1.0 - animation_->GetCurrentValue()) * - view_->height()); + pref_size.height()); // This call makes sure it appears in the right location, the size and shape // is correct and that it slides in the right direction. gfx::Rect find_dlg_rect = GetDialogPosition(gfx::Rect()); - SetDialogPosition(find_dlg_rect); + SetDialogPosition(find_dlg_rect, false); // Let the view know if we are animating, and at which offset to draw the // edges. @@ -409,125 +392,13 @@ void FindBarWin::AnimationEnded(const Animation* animation) { } } -void FindBarWin::OnFindReply(int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update) { - // Ignore responses for requests other than the one we have most recently - // issued. That way we won't act on stale results when the user has - // already typed in another query. - if (view_ && request_id == current_request_id_) { - view_->UpdateMatchCount(number_of_matches, final_update); - view_->UpdateActiveMatchOrdinal(active_match_ordinal); - view_->UpdateResultLabel(); - - // We now need to check if the window is obscuring the search results. - if (!selection_rect.IsEmpty()) - MoveWindowIfNecessary(selection_rect); - - // 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 (number_of_matches > 0) - focus_tracker_.reset(NULL); - } - - // Notify all observers of this notification, such as the automation - // providers which do UI tests for find in page. - FindNotificationDetails detail(request_id, - number_of_matches, - selection_rect, - active_match_ordinal, - final_update); - NotificationService::current()->Notify( - NotificationType::FIND_RESULT_AVAILABLE, - Source<TabContents>(parent_tab_->GetWebContents()), - Details<FindNotificationDetails>(&detail)); -} - -RenderViewHost* FindBarWin::GetRenderViewHost() const { - return parent_tab_->GetWebContents()->render_view_host(); -} - void FindBarWin::GetDialogBounds(gfx::Rect* bounds) { DCHECK(bounds); - - // We need to find the View for the toolbar because we want to visually - // extend it (draw our dialog slightly overlapping its border). - views::View* root_view = views::GetRootViewForHWND(parent_hwnd_); - views::View* toolbar = NULL; - BookmarkBarView* bookmark_bar = NULL; - if (root_view) { - toolbar = root_view->GetViewByID(VIEW_ID_TOOLBAR); - bookmark_bar = static_cast<BookmarkBarView*>( - root_view->GetViewByID(VIEW_ID_BOOKMARK_BAR)); - } - - // To figure out what area we have to work with we need to know the rect for - // the browser window and the page content area starts and get a pointer to - // the toolbar to see where to draw the FindInPage dialog. If any of this - // fails, we return an empty rect. - CRect browser_client_rect, browser_window_rect, content_window_rect; - if (!::IsWindow(parent_hwnd_) || - !::GetWindowRect(parent_tab_->GetContentNativeView(), - &content_window_rect) || - !::GetWindowRect(parent_hwnd_, &browser_window_rect) || - !::GetClientRect(parent_hwnd_, &browser_client_rect) || - !toolbar) { - *bounds = gfx::Rect(); - return; - } - - // Start with browser's client rect, then change it below. - *bounds = gfx::Rect(browser_client_rect); - - // Find the bounds of the toolbar we want to dock to. - gfx::Rect toolbar_bounds; - views::View* bounds_view = NULL; - view_->SetToolbarBlend(true); - if (bookmark_bar && !bookmark_bar->IsDetachedStyle()) { - bounds_view = bookmark_bar; - toolbar_bounds = bookmark_bar->GetLocalBounds(false); - if (bookmark_bar->IsAlwaysShown()) - view_->SetToolbarBlend(false); - } else if (toolbar) { - bounds_view = toolbar; - toolbar_bounds = toolbar->GetLocalBounds(false); - } - - // Figure out at which y coordinate to draw the FindInPage window. If we have - // a toolbar (chrome) we want to overlap it by one pixel so that we look like - // we are part of the chrome (which will also draw our window on top of any - // info-bars, if present). If there is no chrome, then we have a constrained - // window or a Chrome application so we want to draw at the top of the page - // content (right beneath the title bar). - int y_pos_offset = 0; - if (bounds_view) { - // We have a toolbar (chrome), so overlap it by one pixel. - gfx::Point origin; - views::View::ConvertPointToWidget(bounds_view, &origin); - toolbar_bounds.Offset(origin); - y_pos_offset = toolbar_bounds.bottom() - 1; - } else { - // The toolbar isn't visible, so we're in fullscreen mode or this is an app - // window. This means we draw the Find window at the top of the page content - // window. We subtract 1 to overlap the client edge that is part of the - // title bar (so that we don't look detached by 1 pixel). - // TODO(pkasting): This -1 is wrong in maximized mode. - WINDOWINFO wi; - wi.cbSize = sizeof(WINDOWINFO); - GetWindowInfo(parent_hwnd_, &wi); - y_pos_offset = content_window_rect.TopLeft().y - wi.rcClient.top - 1; - } - - bounds->Offset(0, y_pos_offset); - - // We also want to stay well within limits of the vertical scrollbar and not - // draw on the window border (frame) itself either. - int width = views::NativeScrollBar::GetVerticalScrollBarWidth(); - width += kWindowBorderWidth; - bounds->set_x(bounds->x() + width); - bounds->set_width(bounds->width() - (2 * width)); + // 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(); + view_->set_toolbar_blend( + !browser_view_->ShouldFindBarBlendWithBookmarksBar()); } gfx::Rect FindBarWin::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { @@ -567,8 +438,8 @@ gfx::Rect FindBarWin::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { // for the fact that we draw the Find dialog relative to the window, // whereas the selection rect is relative to the page. RECT frame_rect = {0}, webcontents_rect = {0}; - ::GetWindowRect(parent_hwnd_, &frame_rect); - ::GetWindowRect(parent_tab_->GetNativeView(), &webcontents_rect); + ::GetWindowRect(GetParent(), &frame_rect); + ::GetWindowRect(web_contents_->view()->GetNativeView(), &webcontents_rect); avoid_overlapping_rect.Offset(0, webcontents_rect.top - frame_rect.top); } @@ -603,7 +474,7 @@ gfx::Rect FindBarWin::GetDialogPosition(gfx::Rect avoid_overlapping_rect) { return new_pos; } -void FindBarWin::SetDialogPosition(const gfx::Rect& new_pos) { +void FindBarWin::SetDialogPosition(const gfx::Rect& new_pos, bool no_redraw) { if (new_pos.IsEmpty()) return; @@ -612,11 +483,18 @@ void FindBarWin::SetDialogPosition(const gfx::Rect& new_pos) { // of it it doesn't look like the window crumbles into the toolbar. UpdateWindowEdges(new_pos); - ::SetWindowPos(GetHWND(), HWND_TOP, - new_pos.x(), new_pos.y(), new_pos.width(), new_pos.height(), - SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_SHOWWINDOW); + CRect window_rect; + GetWindowRect(&window_rect); + DWORD swp_flags = SWP_NOOWNERZORDER; + if (!window_rect.IsRectEmpty()) + swp_flags |= SWP_NOSIZE; + if (no_redraw) + swp_flags |= SWP_NOREDRAW; + if (!IsVisible()) + swp_flags |= SWP_SHOWWINDOW; - curr_pos_relative_ = new_pos; + ::SetWindowPos(GetHWND(), HWND_TOP, new_pos.x(), new_pos.y(), new_pos.width(), + new_pos.height(), swp_flags); } void FindBarWin::SetFocusChangeListener(HWND parent_hwnd) { @@ -638,7 +516,7 @@ void FindBarWin::SetFocusChangeListener(HWND parent_hwnd) { void FindBarWin::RestoreSavedFocus() { if (focus_tracker_.get() == NULL) { // TODO(brettw) Focus() should be on WebContentsView. - parent_tab_->GetWebContents()->Focus(); + web_contents_->Focus(); } else { focus_tracker_->FocusLastFocusedExternalView(); } @@ -667,3 +545,16 @@ void FindBarWin::UnregisterEscAccelerator() { focus_manager_->RegisterAccelerator(escape, old_accel_target_for_esc_); } +void FindBarWin::UpdateUIForFindResult(const FindNotificationDetails& result, + const std::wstring& find_text) { + 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) + focus_tracker_.reset(NULL); +} |