// 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/infobars/infobar_container.h" #include "app/l10n_util.h" #include "chrome/browser/tab_contents/infobar_delegate.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/infobars/infobars.h" #include "chrome/common/notification_service.h" #include "grit/generated_resources.h" // InfoBarContainer, public: --------------------------------------------------- InfoBarContainer::InfoBarContainer(Delegate* delegate) : delegate_(delegate), tab_contents_(NULL) { SetID(VIEW_ID_INFO_BAR_CONTAINER); SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_INFOBAR_CONTAINER)); } InfoBarContainer::~InfoBarContainer() { // We NULL this pointer before resetting the TabContents to prevent view // hierarchy modifications from attempting to resize the delegate which // could be in the process of shutting down. delegate_ = NULL; ChangeTabContents(NULL); } void InfoBarContainer::ChangeTabContents(TabContents* contents) { registrar_.RemoveAll(); // No need to delete the child views here, their removal from the view // hierarchy does this automatically (see InfoBar::InfoBarRemoved). RemoveAllChildViews(false); tab_contents_ = contents; if (tab_contents_) { UpdateInfoBars(); Source tc_source(tab_contents_); registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, tc_source); registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, tc_source); registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, tc_source); } } void InfoBarContainer::InfoBarAnimated(bool completed) { if (delegate_) delegate_->InfoBarSizeChanged(!completed); } void InfoBarContainer::RemoveDelegate(InfoBarDelegate* delegate) { tab_contents_->RemoveInfoBar(delegate); } // InfoBarContainer, views::View overrides: ------------------------------------ gfx::Size InfoBarContainer::GetPreferredSize() { // We do not have a preferred width (we will expand to fit the available width // of the delegate). Our preferred height is the sum of the preferred // heights of the InfoBars contained within us. int height = 0; for (int i = 0; i < GetChildViewCount(); ++i) height += GetChildViewAt(i)->GetPreferredSize().height(); return gfx::Size(0, height); } void InfoBarContainer::Layout() { int top = 0; for (int i = 0; i < GetChildViewCount(); ++i) { views::View* child = GetChildViewAt(i); gfx::Size ps = child->GetPreferredSize(); child->SetBounds(0, top, width(), ps.height()); top += ps.height(); } } bool InfoBarContainer::GetAccessibleRole(AccessibilityTypes::Role* role) { DCHECK(role); *role = AccessibilityTypes::ROLE_GROUPING; return true; } void InfoBarContainer::ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child) { if (parent == this && child->GetParent() == this) { if (delegate_) { // An InfoBar child was added or removed. Tell the delegate it needs to // re-layout since our preferred size will have changed. delegate_->InfoBarSizeChanged(false); } } } // InfoBarContainer, NotificationObserver implementation: ---------------------- void InfoBarContainer::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { if (type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED) { AddInfoBar(Details(details).ptr(), true); // animated } else if (type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED) { RemoveInfoBar(Details(details).ptr(), true); // animated } else if (type == NotificationType::TAB_CONTENTS_INFOBAR_REPLACED) { std::pair* delegates = Details >(details).ptr(); ReplaceInfoBar(delegates->first, delegates->second); } else { NOTREACHED(); } } // InfoBarContainer, private: -------------------------------------------------- void InfoBarContainer::UpdateInfoBars() { for (int i = 0; i < tab_contents_->infobar_delegate_count(); ++i) { InfoBarDelegate* delegate = tab_contents_->GetInfoBarDelegateAt(i); InfoBar* infobar = delegate->CreateInfoBar(); infobar->set_container(this); AddChildView(infobar); infobar->Open(); } } void InfoBarContainer::AddInfoBar(InfoBarDelegate* delegate, bool use_animation) { InfoBar* infobar = delegate->CreateInfoBar(); infobar->set_container(this); AddChildView(infobar); if (use_animation) infobar->AnimateOpen(); else infobar->Open(); } void InfoBarContainer::RemoveInfoBar(InfoBarDelegate* delegate, bool use_animation) { // Search for infobar associated with |delegate| among child views. // We cannot search for |delegate| in tab_contents, because an infobar remains // a child view until its close animation completes, which can result in // different number of infobars in container and infobar delegates in tab // contents. for (int i = 0; i < GetChildViewCount(); ++i) { InfoBar* infobar = static_cast(GetChildViewAt(i)); if (infobar->delegate() == delegate) { if (use_animation) { // The View will be removed once the Close animation completes. infobar->AnimateClose(); } else { infobar->Close(); } break; } } } void InfoBarContainer::ReplaceInfoBar(InfoBarDelegate* old_delegate, InfoBarDelegate* new_delegate) { RemoveInfoBar(old_delegate, false); // no animation AddInfoBar(new_delegate, false); // no animation }