10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/infobars/core/infobar_container.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "build/build_config.h" 110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/infobars/core/infobar.h" 120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/infobars/core/infobar_delegate.h" 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/slide_animation.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace infobars { 160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InfoBarContainer::Delegate::~Delegate() { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 207dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochInfoBarContainer::InfoBarContainer(Delegate* delegate) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : delegate_(delegate), 22e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_(NULL), 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_arrow_target_height_(InfoBar::kDefaultArrowTargetHeight) { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InfoBarContainer::~InfoBarContainer() { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RemoveAllInfoBarsForDestruction() should have already cleared our infobars. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(infobars_.empty()); 29e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (infobar_manager_) 30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_->RemoveObserver(this); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid InfoBarContainer::ChangeInfoBarManager(InfoBarManager* infobar_manager) { 34e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (infobar_manager_) 35e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_->RemoveObserver(this); 36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Hides all infobars in this container without animation. 38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch while (!infobars_.empty()) { 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch InfoBar* infobar = infobars_.front(); 40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Inform the infobar that it's hidden. If it was already closing, this 41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // deletes it. Otherwise, this ensures the infobar will be deleted if it's 42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // closed while it's not in an InfoBarContainer. 43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch infobar->Hide(false); 44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 46e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_ = infobar_manager; 47e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (infobar_manager_) { 48e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_->AddObserver(this); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 50e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch for (size_t i = 0; i < infobar_manager_->infobar_count(); ++i) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // As when we removed the infobars above, we prevent callbacks to 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // OnInfoBarStateChanged() for each infobar. 53e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch AddInfoBar(infobar_manager_->infobar_at(i), i, false, NO_CALLBACK); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now that everything is up to date, signal the delegate to re-layout. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnInfoBarStateChanged(false); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int InfoBarContainer::GetVerticalOverlap(int* total_height) const { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Our |total_height| is the sum of the preferred heights of the InfoBars 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // contained within us plus the |vertical_overlap|. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int vertical_overlap = 0; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int next_infobar_y = 0; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (InfoBars::const_iterator i(infobars_.begin()); i != infobars_.end(); 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ++i) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InfoBar* infobar = *i; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_infobar_y -= infobar->arrow_height(); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vertical_overlap = std::max(vertical_overlap, -next_infobar_y); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_infobar_y += infobar->total_height(); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (total_height) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *total_height = next_infobar_y + vertical_overlap; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return vertical_overlap; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InfoBarContainer::SetMaxTopArrowHeight(int height) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decrease the height by the arrow stroke thickness, which is the separator 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // line height, because the infobar arrow target heights are without-stroke. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_arrow_target_height_ = std::min( 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(height - InfoBar::kSeparatorLineHeight, 0), 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InfoBar::kMaximumArrowTargetHeight); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateInfoBarArrowTargetHeights(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InfoBarContainer::OnInfoBarStateChanged(bool is_animating) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (delegate_) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_->InfoBarContainerStateChanged(is_animating); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateInfoBarArrowTargetHeights(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformSpecificInfoBarStateChanged(is_animating); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InfoBarContainer::RemoveInfoBar(InfoBar* infobar) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobar->set_container(NULL); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar)); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(i != infobars_.end()); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformSpecificRemoveInfoBar(infobar); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobars_.erase(i); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InfoBarContainer::RemoveAllInfoBarsForDestruction() { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before we remove any children, we reset |delegate_|, so that no removals 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will result in us trying to call 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delegate_->InfoBarContainerStateChanged(). This is important because at 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this point |delegate_| may be shutting down, and it's at best unimportant 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and at worst disastrous to call that. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delegate_ = NULL; 111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch ChangeInfoBarManager(NULL); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InfoBarContainer::OnInfoBarAdded(InfoBar* infobar) { 115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch AddInfoBar(infobar, infobars_.size(), true, WANT_CALLBACK); 116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InfoBarContainer::OnInfoBarRemoved(InfoBar* infobar, bool animate) { 119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch infobar->Hide(animate); 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch UpdateInfoBarArrowTargetHeights(); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InfoBarContainer::OnInfoBarReplaced(InfoBar* old_infobar, 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch InfoBar* new_infobar) { 125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch PlatformSpecificReplaceInfoBar(old_infobar, new_infobar); 126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch InfoBars::const_iterator i(std::find(infobars_.begin(), infobars_.end(), 127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch old_infobar)); 128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK(i != infobars_.end()); 129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch size_t position = i - infobars_.begin(); 130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch old_infobar->Hide(false); 131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch AddInfoBar(new_infobar, position, false, WANT_CALLBACK); 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid InfoBarContainer::OnManagerShuttingDown(InfoBarManager* manager) { 135e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch DCHECK_EQ(infobar_manager_, manager); 136e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_->RemoveObserver(this); 137e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch infobar_manager_ = NULL; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InfoBarContainer::AddInfoBar(InfoBar* infobar, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t position, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool animate, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CallbackStatus callback_status) { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(std::find(infobars_.begin(), infobars_.end(), infobar) == 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobars_.end()); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(position, infobars_.size()); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobars_.insert(infobars_.begin() + position, infobar); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateInfoBarArrowTargetHeights(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlatformSpecificAddInfoBar(infobar, position); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_status == WANT_CALLBACK) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobar->set_container(this); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobar->Show(animate); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_status == NO_CALLBACK) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobar->set_container(this); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InfoBarContainer::UpdateInfoBarArrowTargetHeights() { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < infobars_.size(); ++i) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) infobars_[i]->SetArrowTargetHeight(ArrowTargetHeightForInfoBar(i)); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int InfoBarContainer::ArrowTargetHeightForInfoBar(size_t infobar_index) const { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!delegate_ || !delegate_->DrawInfoBarArrows(NULL)) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (infobar_index == 0) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return top_arrow_target_height_; 167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const gfx::SlideAnimation& first_infobar_animation = 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const_cast<const InfoBar*>(infobars_.front())->animation(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((infobar_index > 1) || first_infobar_animation.IsShowing()) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return InfoBar::kDefaultArrowTargetHeight; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the first infobar is animating closed, we animate the second infobar's 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // arrow target height from the default to the top target height. Note that 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the animation values here are going from 1.0 -> 0.0 as the top bar closes. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return top_arrow_target_height_ + static_cast<int>( 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (InfoBar::kDefaultArrowTargetHeight - top_arrow_target_height_) * 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_infobar_animation.GetCurrentValue()); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} // namespace infobars 180