1 // Copyright 2014 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 "components/infobars/core/infobar_container.h"
9 #include "base/auto_reset.h"
10 #include "base/logging.h"
11 #include "build/build_config.h"
12 #include "components/infobars/core/infobar.h"
13 #include "components/infobars/core/infobar_delegate.h"
17 InfoBarContainer::Delegate::~Delegate() {
20 InfoBarContainer::InfoBarContainer(Delegate
* delegate
)
21 : delegate_(delegate
),
22 infobar_manager_(NULL
),
23 ignore_infobar_state_changed_(false) {
26 InfoBarContainer::~InfoBarContainer() {
27 // RemoveAllInfoBarsForDestruction() should have already cleared our infobars.
28 DCHECK(infobars_
.empty());
30 infobar_manager_
->RemoveObserver(this);
33 void InfoBarContainer::ChangeInfoBarManager(InfoBarManager
* infobar_manager
) {
35 infobar_manager_
->RemoveObserver(this);
38 // Ignore intermediate state changes. We'll manually trigger processing
39 // once we're finished.
40 base::AutoReset
<bool> ignore_changes(&ignore_infobar_state_changed_
, true);
42 // Hides all infobars in this container without animation.
43 while (!infobars_
.empty()) {
44 InfoBar
* infobar
= infobars_
.front();
45 // Inform the infobar that it's hidden. If it was already closing, this
46 // deletes it. Otherwise, this ensures the infobar will be deleted if
47 // it's closed while it's not in an InfoBarContainer.
51 infobar_manager_
= infobar_manager
;
52 if (infobar_manager_
) {
53 infobar_manager_
->AddObserver(this);
55 for (size_t i
= 0; i
< infobar_manager_
->infobar_count(); ++i
)
56 AddInfoBar(infobar_manager_
->infobar_at(i
), i
, false);
60 // Now that everything is up to date, signal the delegate to re-layout.
61 OnInfoBarStateChanged(false);
64 int InfoBarContainer::GetVerticalOverlap(int* total_height
) const {
65 // Our |total_height| is the sum of the preferred heights of the InfoBars
66 // contained within us plus the |vertical_overlap|.
67 int vertical_overlap
= 0;
68 int next_infobar_y
= 0;
70 for (InfoBars::const_iterator
i(infobars_
.begin()); i
!= infobars_
.end();
72 InfoBar
* infobar
= *i
;
73 next_infobar_y
-= infobar
->arrow_height();
74 vertical_overlap
= std::max(vertical_overlap
, -next_infobar_y
);
75 next_infobar_y
+= infobar
->total_height();
79 *total_height
= next_infobar_y
+ vertical_overlap
;
80 return vertical_overlap
;
83 void InfoBarContainer::UpdateInfoBarArrowTargetHeights() {
84 for (size_t i
= 0; i
< infobars_
.size(); ++i
) {
85 infobars_
[i
]->SetArrowTargetHeight(delegate_
?
86 delegate_
->ArrowTargetHeightForInfoBar(
87 i
, const_cast<const InfoBar
*>(infobars_
[i
])->animation()) : 0);
91 void InfoBarContainer::OnInfoBarStateChanged(bool is_animating
) {
92 if (ignore_infobar_state_changed_
)
95 delegate_
->InfoBarContainerStateChanged(is_animating
);
96 UpdateInfoBarArrowTargetHeights();
97 PlatformSpecificInfoBarStateChanged(is_animating
);
100 void InfoBarContainer::RemoveInfoBar(InfoBar
* infobar
) {
101 infobar
->set_container(NULL
);
102 InfoBars::iterator
i(std::find(infobars_
.begin(), infobars_
.end(), infobar
));
103 DCHECK(i
!= infobars_
.end());
104 PlatformSpecificRemoveInfoBar(infobar
);
108 void InfoBarContainer::RemoveAllInfoBarsForDestruction() {
109 // Before we remove any children, we reset |delegate_|, so that no removals
110 // will result in us trying to call
111 // delegate_->InfoBarContainerStateChanged(). This is important because at
112 // this point |delegate_| may be shutting down, and it's at best unimportant
113 // and at worst disastrous to call that.
115 ChangeInfoBarManager(NULL
);
118 void InfoBarContainer::OnInfoBarAdded(InfoBar
* infobar
) {
119 AddInfoBar(infobar
, infobars_
.size(), true);
122 void InfoBarContainer::OnInfoBarRemoved(InfoBar
* infobar
, bool animate
) {
123 infobar
->Hide(animate
);
124 UpdateInfoBarArrowTargetHeights();
127 void InfoBarContainer::OnInfoBarReplaced(InfoBar
* old_infobar
,
128 InfoBar
* new_infobar
) {
129 PlatformSpecificReplaceInfoBar(old_infobar
, new_infobar
);
130 InfoBars::const_iterator
i(std::find(infobars_
.begin(), infobars_
.end(),
132 DCHECK(i
!= infobars_
.end());
133 size_t position
= i
- infobars_
.begin();
134 old_infobar
->Hide(false);
135 AddInfoBar(new_infobar
, position
, false);
138 void InfoBarContainer::OnManagerShuttingDown(InfoBarManager
* manager
) {
139 DCHECK_EQ(infobar_manager_
, manager
);
140 infobar_manager_
->RemoveObserver(this);
141 infobar_manager_
= NULL
;
144 void InfoBarContainer::AddInfoBar(InfoBar
* infobar
,
147 DCHECK(std::find(infobars_
.begin(), infobars_
.end(), infobar
) ==
149 DCHECK_LE(position
, infobars_
.size());
150 infobars_
.insert(infobars_
.begin() + position
, infobar
);
151 UpdateInfoBarArrowTargetHeights();
152 PlatformSpecificAddInfoBar(infobar
, position
);
153 infobar
->set_container(this);
154 infobar
->Show(animate
);
157 } // namespace infobars