1// Copyright (c) 2011 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.
4
5#ifndef CHROME_BROWSER_INFOBARS_INFOBAR_CONTAINER_H_
6#define CHROME_BROWSER_INFOBARS_INFOBAR_CONTAINER_H_
7
8#include <vector>
9
10#include "base/compiler_specific.h"
11#include "base/time/time.h"
12#include "content/public/browser/notification_observer.h"
13#include "content/public/browser/notification_registrar.h"
14#include "third_party/skia/include/core/SkColor.h"
15
16class InfoBar;
17class InfoBarService;
18
19// InfoBarContainer is a cross-platform base class to handle the visibility-
20// related aspects of InfoBars.  While InfoBarService owns the InfoBars, the
21// InfoBarContainer is responsible for telling particular InfoBars that they
22// should be hidden or visible.
23//
24// Platforms need to subclass this to implement a few platform-specific
25// functions, which are pure virtual here.
26class InfoBarContainer : public content::NotificationObserver {
27 public:
28  class Delegate {
29   public:
30    // The separator color may vary depending on where the container is hosted.
31    virtual SkColor GetInfoBarSeparatorColor() const = 0;
32
33    // The delegate is notified each time the infobar container changes height,
34    // as well as when it stops animating.
35    virtual void InfoBarContainerStateChanged(bool is_animating) = 0;
36
37    // The delegate needs to tell us whether "unspoofable" arrows should be
38    // drawn, and if so, at what |x| coordinate.  |x| may be NULL.
39    virtual bool DrawInfoBarArrows(int* x) const = 0;
40
41   protected:
42    virtual ~Delegate();
43  };
44
45  explicit InfoBarContainer(Delegate* delegate);
46  virtual ~InfoBarContainer();
47
48  // Changes the InfoBarService for which this container is showing infobars.
49  // This will hide all current infobars, remove them from the container, add
50  // the infobars from |infobar_service|, and show them all.  |infobar_service|
51  // may be NULL.
52  void ChangeInfoBarService(InfoBarService* infobar_service);
53
54  // Returns the amount by which to overlap the toolbar above, and, when
55  // |total_height| is non-NULL, set it to the height of the InfoBarContainer
56  // (including overlap).
57  int GetVerticalOverlap(int* total_height);
58
59  // Called by the delegate when the distance between what the top infobar's
60  // "unspoofable" arrow would point to and the top infobar itself changes.
61  // This enables the top infobar to show a longer arrow (e.g. because of a
62  // visible bookmark bar) or shorter (e.g. due to being in a popup window) if
63  // desired.
64  //
65  // IMPORTANT: This MUST NOT result in a call back to
66  // Delegate::InfoBarContainerStateChanged() unless it causes an actual
67  // change, lest we infinitely recurse.
68  void SetMaxTopArrowHeight(int height);
69
70  // Called when a contained infobar has animated or by some other means changed
71  // its height, or when it stops animating.  The container is expected to do
72  // anything necessary to respond, e.g. re-layout.
73  void OnInfoBarStateChanged(bool is_animating);
74
75  // Called by |infobar| to request that it be removed from the container.  At
76  // this point, |infobar| should already be hidden.
77  void RemoveInfoBar(InfoBar* infobar);
78
79  const Delegate* delegate() const { return delegate_; }
80
81 protected:
82  // Subclasses must call this during destruction, so that we can remove
83  // infobars (which will call the pure virtual functions below) while the
84  // subclass portion of |this| has not yet been destroyed.
85  void RemoveAllInfoBarsForDestruction();
86
87  // These must be implemented on each platform to e.g. adjust the visible
88  // object hierarchy.  The first two functions should each be called exactly
89  // once during an infobar's life (see comments on RemoveInfoBar() and
90  // AddInfoBar()).
91  virtual void PlatformSpecificAddInfoBar(InfoBar* infobar,
92                                          size_t position) = 0;
93  // TODO(miguelg): Remove this; it is only necessary for Android, and only
94  // until the translate infobar is implemented as three different infobars like
95  // GTK does.
96  virtual void PlatformSpecificReplaceInfoBar(InfoBar* old_infobar,
97                                              InfoBar* new_infobar) {}
98  virtual void PlatformSpecificRemoveInfoBar(InfoBar* infobar) = 0;
99  virtual void PlatformSpecificInfoBarStateChanged(bool is_animating) {}
100
101 private:
102  typedef std::vector<InfoBar*> InfoBars;
103
104  // content::NotificationObserver:
105  virtual void Observe(int type,
106                       const content::NotificationSource& source,
107                       const content::NotificationDetails& details) OVERRIDE;
108
109  // Hides all infobars in this container without animation.
110  void HideAllInfoBars();
111
112  // Adds |infobar| to this container before the existing infobar at position
113  // |position| and calls Show() on it.  |animate| is passed along to
114  // infobar->Show().  Depending on the value of |callback_status|, this calls
115  // infobar->set_container(this) either before or after the call to Show() so
116  // that OnInfoBarStateChanged() either will or won't be called as a result.
117  enum CallbackStatus { NO_CALLBACK, WANT_CALLBACK };
118  void AddInfoBar(InfoBar* infobar,
119                  size_t position,
120                  bool animate,
121                  CallbackStatus callback_status);
122
123  void UpdateInfoBarArrowTargetHeights();
124  int ArrowTargetHeightForInfoBar(size_t infobar_index) const;
125
126  content::NotificationRegistrar registrar_;
127  Delegate* delegate_;
128  InfoBarService* infobar_service_;
129  InfoBars infobars_;
130
131  // Calculated in SetMaxTopArrowHeight().
132  int top_arrow_target_height_;
133
134  DISALLOW_COPY_AND_ASSIGN(InfoBarContainer);
135};
136
137#endif  // CHROME_BROWSER_INFOBARS_INFOBAR_CONTAINER_H_
138