blob: fb5cf3b254401979d9a68d7010919583b4ab6cf0 [file] [log] [blame]
// Copyright (c) 2009 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/find_bar_controller.h"
#include "build/build_config.h"
#include "chrome/browser/find_bar.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/common/notification_service.h"
#include "chrome/browser/tab_contents/web_contents.h"
FindBarController::FindBarController(FindBar* find_bar)
: find_bar_(find_bar), web_contents_(NULL) {
}
FindBarController::~FindBarController() {
// Web contents should have been NULLed out. If not, then we're leaking
// notification observers.
DCHECK(!web_contents_);
}
void FindBarController::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);
find_bar_->Show();
}
find_bar_->SetFocusAndSelection();
}
void FindBarController::EndFindSession() {
find_bar_->Hide(true);
// |web_contents_| can be NULL for a number of reasons, for example when the
// tab is closing. We must guard against that case. See issue 8030.
if (web_contents_) {
// 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.
find_bar_->ClearResults(web_contents_->find_result());
// When we get dismissed we restore the focus to where it belongs.
find_bar_->RestoreSavedFocus();
}
}
void FindBarController::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()));
find_bar_->StopAnimation();
}
web_contents_ = contents;
// Hide any visible find window from the previous tab if NULL |web_contents|
// is passed in or if the find UI is not active in the new tab.
if (find_bar_->IsFindBarVisible() &&
(!web_contents_ || !web_contents_->find_ui_active())) {
find_bar_->Hide(false);
}
if (web_contents_) {
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()));
// Find out what we should show in the find text box. Usually, this will be
// the last search in this tab, but if no search has been issued in this tab
// we use the last search string (from any tab).
string16 find_string = web_contents_->find_text();
if (find_string.empty())
find_string = web_contents_->find_prepopulate_text();
// 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.
find_bar_->SetFindText(find_string);
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 = find_bar_->GetDialogPosition(gfx::Rect());
find_bar_->SetDialogPosition(new_pos, false);
// Only modify focus and selection if Find is active, otherwise the Find
// Bar will interfere with user input.
find_bar_->SetFocusAndSelection();
}
find_bar_->UpdateUIForFindResult(web_contents_->find_result(),
web_contents_->find_text());
}
}
////////////////////////////////////////////////////////////////////////////////
// FindBarWin, NotificationObserver implementation:
void FindBarController::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_) {
find_bar_->UpdateUIForFindResult(web_contents_->find_result(),
web_contents_->find_text());
}
} 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 (find_bar_->IsFindBarVisible()) {
if (PageTransition::StripQualifier(transition_type) !=
PageTransition::RELOAD) {
EndFindSession();
} else {
// On Reload we want to make sure FindNext is converted to a full Find
// to make sure highlights for inactive matches are repainted.
web_contents_->set_find_op_aborted(true);
}
}
}
}
}