Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / infobars / infobar_container.cc
blobf9713e5dbed5ad33a43a00cc5b59d31a0478626a
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "build/build_config.h"
7 #include "chrome/browser/infobars/infobar_container.h"
9 #include <algorithm>
11 #include "base/logging.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/infobars/infobar.h"
14 #include "chrome/browser/infobars/infobar_delegate.h"
15 #include "chrome/browser/infobars/infobar_service.h"
16 #include "content/public/browser/notification_details.h"
17 #include "content/public/browser/notification_source.h"
18 #include "ui/gfx/animation/slide_animation.h"
20 InfoBarContainer::Delegate::~Delegate() {
23 InfoBarContainer::InfoBarContainer(Delegate* delegate)
24 : delegate_(delegate),
25 infobar_service_(NULL),
26 top_arrow_target_height_(InfoBar::kDefaultArrowTargetHeight) {
29 InfoBarContainer::~InfoBarContainer() {
30 // RemoveAllInfoBarsForDestruction() should have already cleared our infobars.
31 DCHECK(infobars_.empty());
34 void InfoBarContainer::ChangeInfoBarService(InfoBarService* infobar_service) {
35 HideAllInfoBars();
37 infobar_service_ = infobar_service;
38 if (infobar_service_) {
39 content::Source<InfoBarService> source(infobar_service_);
40 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
41 source);
42 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
43 source);
44 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
45 source);
47 for (size_t i = 0; i < infobar_service_->infobar_count(); ++i) {
48 // As when we removed the infobars above, we prevent callbacks to
49 // OnInfoBarAnimated() for each infobar.
50 AddInfoBar(infobar_service_->infobar_at(i), i, false, NO_CALLBACK);
54 // Now that everything is up to date, signal the delegate to re-layout.
55 OnInfoBarStateChanged(false);
58 int InfoBarContainer::GetVerticalOverlap(int* total_height) {
59 // Our |total_height| is the sum of the preferred heights of the InfoBars
60 // contained within us plus the |vertical_overlap|.
61 int vertical_overlap = 0;
62 int next_infobar_y = 0;
64 for (InfoBars::iterator i(infobars_.begin()); i != infobars_.end(); ++i) {
65 InfoBar* infobar = *i;
66 next_infobar_y -= infobar->arrow_height();
67 vertical_overlap = std::max(vertical_overlap, -next_infobar_y);
68 next_infobar_y += infobar->total_height();
71 if (total_height)
72 *total_height = next_infobar_y + vertical_overlap;
73 return vertical_overlap;
76 void InfoBarContainer::SetMaxTopArrowHeight(int height) {
77 // Decrease the height by the arrow stroke thickness, which is the separator
78 // line height, because the infobar arrow target heights are without-stroke.
79 top_arrow_target_height_ = std::min(
80 std::max(height - InfoBar::kSeparatorLineHeight, 0),
81 InfoBar::kMaximumArrowTargetHeight);
82 UpdateInfoBarArrowTargetHeights();
85 void InfoBarContainer::OnInfoBarStateChanged(bool is_animating) {
86 if (delegate_)
87 delegate_->InfoBarContainerStateChanged(is_animating);
88 UpdateInfoBarArrowTargetHeights();
89 PlatformSpecificInfoBarStateChanged(is_animating);
92 void InfoBarContainer::RemoveInfoBar(InfoBar* infobar) {
93 infobar->set_container(NULL);
94 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar));
95 DCHECK(i != infobars_.end());
96 PlatformSpecificRemoveInfoBar(infobar);
97 infobars_.erase(i);
100 void InfoBarContainer::RemoveAllInfoBarsForDestruction() {
101 // Before we remove any children, we reset |delegate_|, so that no removals
102 // will result in us trying to call
103 // delegate_->InfoBarContainerStateChanged(). This is important because at
104 // this point |delegate_| may be shutting down, and it's at best unimportant
105 // and at worst disastrous to call that.
106 delegate_ = NULL;
107 ChangeInfoBarService(NULL);
110 void InfoBarContainer::Observe(int type,
111 const content::NotificationSource& source,
112 const content::NotificationDetails& details) {
113 switch (type) {
114 case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED:
115 AddInfoBar(content::Details<InfoBar::AddedDetails>(details).ptr(),
116 infobars_.size(), true, WANT_CALLBACK);
117 break;
119 case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED: {
120 InfoBar::RemovedDetails* removed_details =
121 content::Details<InfoBar::RemovedDetails>(details).ptr();
122 removed_details->first->Hide(removed_details->second);
123 UpdateInfoBarArrowTargetHeights();
124 break;
127 case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED: {
128 InfoBar::ReplacedDetails* replaced_details =
129 content::Details<InfoBar::ReplacedDetails>(details).ptr();
130 InfoBar* old_infobar = replaced_details->first;
131 InfoBar* new_infobar = replaced_details->second;
132 PlatformSpecificReplaceInfoBar(old_infobar, new_infobar);
133 InfoBars::const_iterator i(std::find(infobars_.begin(), infobars_.end(),
134 old_infobar));
135 DCHECK(i != infobars_.end());
136 size_t position = i - infobars_.begin();
137 old_infobar->Hide(false);
138 AddInfoBar(new_infobar, position, false, WANT_CALLBACK);
139 break;
142 default:
143 NOTREACHED();
144 break;
148 void InfoBarContainer::HideAllInfoBars() {
149 registrar_.RemoveAll();
151 while (!infobars_.empty()) {
152 InfoBar* infobar = infobars_.front();
153 // Inform the infobar that it's hidden. If it was already closing, this
154 // deletes it. Otherwise, this ensures the infobar will be deleted if it's
155 // closed while it's not in an InfoBarContainer.
156 infobar->Hide(false);
160 void InfoBarContainer::AddInfoBar(InfoBar* infobar,
161 size_t position,
162 bool animate,
163 CallbackStatus callback_status) {
164 DCHECK(std::find(infobars_.begin(), infobars_.end(), infobar) ==
165 infobars_.end());
166 DCHECK_LE(position, infobars_.size());
167 infobars_.insert(infobars_.begin() + position, infobar);
168 UpdateInfoBarArrowTargetHeights();
169 PlatformSpecificAddInfoBar(infobar, position);
170 if (callback_status == WANT_CALLBACK)
171 infobar->set_container(this);
172 infobar->Show(animate);
173 if (callback_status == NO_CALLBACK)
174 infobar->set_container(this);
177 void InfoBarContainer::UpdateInfoBarArrowTargetHeights() {
178 for (size_t i = 0; i < infobars_.size(); ++i)
179 infobars_[i]->SetArrowTargetHeight(ArrowTargetHeightForInfoBar(i));
182 int InfoBarContainer::ArrowTargetHeightForInfoBar(size_t infobar_index) const {
183 if (!delegate_ || !delegate_->DrawInfoBarArrows(NULL))
184 return 0;
185 if (infobar_index == 0)
186 return top_arrow_target_height_;
187 const gfx::SlideAnimation& first_infobar_animation =
188 const_cast<const InfoBar*>(infobars_.front())->animation();
189 if ((infobar_index > 1) || first_infobar_animation.IsShowing())
190 return InfoBar::kDefaultArrowTargetHeight;
191 // When the first infobar is animating closed, we animate the second infobar's
192 // arrow target height from the default to the top target height. Note that
193 // the animation values here are going from 1.0 -> 0.0 as the top bar closes.
194 return top_arrow_target_height_ + static_cast<int>(
195 (InfoBar::kDefaultArrowTargetHeight - top_arrow_target_height_) *
196 first_infobar_animation.GetCurrentValue());