diff options
author | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-01 15:24:08 +0000 |
---|---|---|
committer | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-01 15:24:08 +0000 |
commit | 2f93641aca552e88c4810924fe2135b626707b45 (patch) | |
tree | 26b29b0da55fb33174def9948f0bbdb859161edd /chrome/browser/infobars | |
parent | 678e68ab1a5fa99f07634cce9ac22a6d700436df (diff) | |
download | chromium_src-2f93641aca552e88c4810924fe2135b626707b45.zip chromium_src-2f93641aca552e88c4810924fe2135b626707b45.tar.gz chromium_src-2f93641aca552e88c4810924fe2135b626707b45.tar.bz2 |
Move infobar handling to a tab helper, part 1.
BUG=94741
TEST=no visible change
Review URL: http://codereview.chromium.org/7810002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99187 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/infobars')
-rw-r--r-- | chrome/browser/infobars/infobar_tab_helper.cc | 199 | ||||
-rw-r--r-- | chrome/browser/infobars/infobar_tab_helper.h | 81 |
2 files changed, 280 insertions, 0 deletions
diff --git a/chrome/browser/infobars/infobar_tab_helper.cc b/chrome/browser/infobars/infobar_tab_helper.cc new file mode 100644 index 0000000..4109189 --- /dev/null +++ b/chrome/browser/infobars/infobar_tab_helper.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2011 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/infobars/infobar_tab_helper.h" + +#include "chrome/browser/tab_contents/infobar.h" +#include "chrome/browser/tab_contents/infobar_delegate.h" +#include "chrome/browser/tab_contents/insecure_content_infobar_delegate.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/render_messages.h" +#include "content/common/notification_service.h" +#include "content/browser/tab_contents/tab_contents.h" + +InfoBarTabHelper::InfoBarTabHelper(TabContentsWrapper* tab_contents) + : TabContentsObserver(tab_contents->tab_contents()), + infobars_enabled_(true), + tab_contents_wrapper_(tab_contents) { + DCHECK(tab_contents); +} + +InfoBarTabHelper::~InfoBarTabHelper() { + // Destroy all remaining InfoBars. It's important to not animate here so that + // we guarantee that we'll delete all delegates before we do anything else. + // + // TODO(pkasting): If there is no InfoBarContainer, this leaks all the + // InfoBarDelegates. This will be fixed once we call CloseSoon() directly on + // Infobars. + RemoveAllInfoBars(false); +} + +void InfoBarTabHelper::AddInfoBar(InfoBarDelegate* delegate) { + if (!infobars_enabled_) { + delegate->InfoBarClosed(); + return; + } + + for (size_t i = 0; i < infobars_.size(); ++i) { + if (GetInfoBarDelegateAt(i)->EqualsDelegate(delegate)) { + delegate->InfoBarClosed(); + return; + } + } + + infobars_.push_back(delegate); + NotificationService::current()->Notify( + chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, + Source<TabContentsWrapper>(tab_contents_wrapper_), + Details<InfoBarAddedDetails>(delegate)); + + // Add ourselves as an observer for navigations the first time a delegate is + // added. We use this notification to expire InfoBars that need to expire on + // page transitions. + if (infobars_.size() == 1) { + registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, + Source<NavigationController>(&tab_contents()->controller())); + } +} + +void InfoBarTabHelper::RemoveInfoBar(InfoBarDelegate* delegate) { + RemoveInfoBarInternal(delegate, true); +} + +void InfoBarTabHelper::ReplaceInfoBar(InfoBarDelegate* old_delegate, + InfoBarDelegate* new_delegate) { + if (!infobars_enabled_) { + AddInfoBar(new_delegate); // Deletes the delegate. + return; + } + + size_t i; + for (i = 0; i < infobars_.size(); ++i) { + if (GetInfoBarDelegateAt(i) == old_delegate) + break; + } + DCHECK_LT(i, infobars_.size()); + + infobars_.insert(infobars_.begin() + i, new_delegate); + + old_delegate->clear_owner(); + InfoBarReplacedDetails replaced_details(old_delegate, new_delegate); + NotificationService::current()->Notify( + chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED, + Source<TabContentsWrapper>(tab_contents_wrapper_), + Details<InfoBarReplacedDetails>(&replaced_details)); + + infobars_.erase(infobars_.begin() + i + 1); +} + +InfoBarDelegate* InfoBarTabHelper::GetInfoBarDelegateAt(size_t index) { + return infobars_[index]; +} + +void InfoBarTabHelper::RemoveInfoBarInternal(InfoBarDelegate* delegate, + bool animate) { + if (!infobars_enabled_) { + DCHECK(infobars_.empty()); + return; + } + + size_t i; + for (i = 0; i < infobars_.size(); ++i) { + if (GetInfoBarDelegateAt(i) == delegate) + break; + } + DCHECK_LT(i, infobars_.size()); + InfoBarDelegate* infobar = infobars_[i]; + + infobar->clear_owner(); + InfoBarRemovedDetails removed_details(infobar, animate); + NotificationService::current()->Notify( + chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, + Source<TabContentsWrapper>(tab_contents_wrapper_), + Details<InfoBarRemovedDetails>(&removed_details)); + + infobars_.erase(infobars_.begin() + i); + // Remove ourselves as an observer if we are tracking no more InfoBars. + if (infobars_.empty()) { + registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, + Source<NavigationController>(&tab_contents()->controller())); + } +} + +void InfoBarTabHelper::RemoveAllInfoBars(bool animate) { + while (!infobars_.empty()) + RemoveInfoBarInternal(GetInfoBarDelegateAt(infobar_count() - 1), animate); +} + +void InfoBarTabHelper::OnDidBlockDisplayingInsecureContent() { + // At most one infobar and do not supersede the stronger running content bar. + for (size_t i = 0; i < infobars_.size(); ++i) { + if (GetInfoBarDelegateAt(i)->AsInsecureContentInfoBarDelegate()) + return; + } + AddInfoBar(new InsecureContentInfoBarDelegate(tab_contents_wrapper_, + InsecureContentInfoBarDelegate::DISPLAY)); +} + +void InfoBarTabHelper::OnDidBlockRunningInsecureContent() { + // At most one infobar superseding any weaker displaying content bar. + for (size_t i = 0; i < infobars_.size(); ++i) { + InsecureContentInfoBarDelegate* delegate = + GetInfoBarDelegateAt(i)->AsInsecureContentInfoBarDelegate(); + if (delegate) { + if (delegate->type() != InsecureContentInfoBarDelegate::RUN) { + ReplaceInfoBar(delegate, new InsecureContentInfoBarDelegate( + tab_contents_wrapper_, + InsecureContentInfoBarDelegate::RUN)); + } + return; + } + } + AddInfoBar(new InsecureContentInfoBarDelegate(tab_contents_wrapper_, + InsecureContentInfoBarDelegate::RUN)); +} + +void InfoBarTabHelper::RenderViewGone() { + RemoveAllInfoBars(true); +} + +bool InfoBarTabHelper::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(InfoBarTabHelper, message) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidBlockDisplayingInsecureContent, + OnDidBlockDisplayingInsecureContent) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidBlockRunningInsecureContent, + OnDidBlockRunningInsecureContent) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void InfoBarTabHelper::Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type) { + case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { + DCHECK(&tab_contents()->controller() == + Source<NavigationController>(source).ptr()); + + content::LoadCommittedDetails& committed_details = + *(Details<content::LoadCommittedDetails>(details).ptr()); + + // NOTE: It is not safe to change the following code to count upwards or + // use iterators, as the RemoveInfoBar() call synchronously modifies our + // delegate list. + for (size_t i = infobars_.size(); i > 0; --i) { + InfoBarDelegate* delegate = GetInfoBarDelegateAt(i - 1); + if (delegate->ShouldExpire(committed_details)) + RemoveInfoBar(delegate); + } + + break; + } + default: + NOTREACHED(); + } +} diff --git a/chrome/browser/infobars/infobar_tab_helper.h b/chrome/browser/infobars/infobar_tab_helper.h new file mode 100644 index 0000000..9d15d36 --- /dev/null +++ b/chrome/browser/infobars/infobar_tab_helper.h @@ -0,0 +1,81 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_INFOBARS_INFOBAR_TAB_HELPER_H_ +#define CHROME_BROWSER_INFOBARS_INFOBAR_TAB_HELPER_H_ +#pragma once + +#include "base/basictypes.h" +#include "content/browser/tab_contents/tab_contents_observer.h" +#include "content/common/notification_registrar.h" + +class InfoBarDelegate; +class TabContentsWrapper; + +// Per-tab info bar manager. +class InfoBarTabHelper : public TabContentsObserver, + public NotificationObserver { + public: + explicit InfoBarTabHelper(TabContentsWrapper* tab_contents); + virtual ~InfoBarTabHelper(); + + // Adds an InfoBar for the specified |delegate|. + // + // If infobars are disabled for this tab or the tab already has a delegate + // which returns true for InfoBarDelegate::EqualsDelegate(delegate), + // |delegate| is closed immediately without being added. + void AddInfoBar(InfoBarDelegate* delegate); + + // Removes the InfoBar for the specified |delegate|. + // + // If infobars are disabled for this tab, this will do nothing, on the + // assumption that the matching AddInfoBar() call will have already closed the + // delegate (see above). + void RemoveInfoBar(InfoBarDelegate* delegate); + + // Replaces one infobar with another, without any animation in between. + // + // If infobars are disabled for this tab, |new_delegate| is closed immediately + // without being added, and nothing else happens. + // + // NOTE: This does not perform any EqualsDelegate() checks like AddInfoBar(). + void ReplaceInfoBar(InfoBarDelegate* old_delegate, + InfoBarDelegate* new_delegate); + + // Enumeration and access functions. + size_t infobar_count() const { return infobars_.size(); } + // WARNING: This does not sanity-check |index|! + InfoBarDelegate* GetInfoBarDelegateAt(size_t index); + void set_infobars_enabled(bool value) { infobars_enabled_ = value; } + + // TabContentsObserver overrides: + virtual void RenderViewGone() OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // NotificationObserver overrides: + virtual void Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) OVERRIDE; + + private: + void RemoveInfoBarInternal(InfoBarDelegate* delegate, bool animate); + void RemoveAllInfoBars(bool animate); + + // Message handlers. + void OnDidBlockDisplayingInsecureContent(); + void OnDidBlockRunningInsecureContent(); + + // Delegates for InfoBars associated with this InfoBarTabHelper. + std::vector<InfoBarDelegate*> infobars_; + bool infobars_enabled_; + + NotificationRegistrar registrar_; + + // Owning TabContentsWrapper. + TabContentsWrapper* tab_contents_wrapper_; + + DISALLOW_COPY_AND_ASSIGN(InfoBarTabHelper); +}; + +#endif // CHROME_BROWSER_INFOBARS_INFOBAR_TAB_HELPER_H_ |