status_bubble_mac.h revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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_UI_COCOA_STATUS_BUBBLE_MAC_H_
6#define CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
7
8#include <string>
9
10#import <Cocoa/Cocoa.h>
11#import <QuartzCore/QuartzCore.h>
12
13#include "base/compiler_specific.h"
14#include "base/memory/weak_ptr.h"
15#include "base/strings/string16.h"
16#include "chrome/browser/ui/status_bubble.h"
17#include "url/gurl.h"
18
19class StatusBubbleMacTest;
20
21class StatusBubbleMac : public StatusBubble {
22 public:
23  // The various states that a status bubble may be in.  Public for delegate
24  // access (for testing).
25  enum StatusBubbleState {
26    kBubbleHidden,         // Fully hidden
27    kBubbleShowingTimer,   // Waiting to fade in
28    kBubbleShowingFadeIn,  // In a fade-in transition
29    kBubbleShown,          // Fully visible
30    kBubbleHidingTimer,    // Waiting to fade out
31    kBubbleHidingFadeOut   // In a fade-out transition
32  };
33
34  StatusBubbleMac(NSWindow* parent, id delegate);
35  virtual ~StatusBubbleMac();
36
37  // StatusBubble implementation.
38  virtual void SetStatus(const base::string16& status) OVERRIDE;
39  virtual void SetURL(const GURL& url, const std::string& languages) OVERRIDE;
40  virtual void Hide() OVERRIDE;
41  virtual void MouseMoved(const gfx::Point& location,
42                          bool left_content) OVERRIDE;
43  virtual void UpdateDownloadShelfVisibility(bool visible) OVERRIDE;
44
45  // Mac-specific method: Update the size and position of the status bubble to
46  // match the parent window. Safe to call even when the status bubble does not
47  // exist.
48  void UpdateSizeAndPosition();
49
50  // Mac-specific method: Change the parent window of the status bubble. Safe to
51  // call even when the status bubble does not exist.
52  void SwitchParentWindow(NSWindow* parent);
53
54  // Delegate method called when a fade-in or fade-out transition has
55  // completed.  This is public so that it may be visible to the CAAnimation
56  // delegate, which is an Objective-C object.
57  void AnimationDidStop(CAAnimation* animation, bool finished);
58
59  // Expand the bubble to fit a URL too long for the standard bubble size.
60  void ExpandBubble();
61
62 protected:
63  // Get the current location of the mouse. Protected so that it can be
64  // stubbed out for testing.
65  virtual gfx::Point GetMouseLocation();
66
67 private:
68  friend class StatusBubbleMacTest;
69
70  // Setter for state_.  Use this instead of writing to state_ directly so
71  // that state changes can be observed by unit tests.
72  void SetState(StatusBubbleState state);
73
74  // Sets the bubble text for SetStatus and SetURL.
75  void SetText(const base::string16& text, bool is_url);
76
77  // Construct the window/widget if it does not already exist. (Safe to call if
78  // it does.)
79  void Create();
80
81  // Attaches the status bubble window to its parent window. Safe to call even
82  // when already attached.
83  void Attach();
84
85  // Detaches the status bubble window from its parent window.
86  void Detach();
87
88  // Is the status bubble attached to the browser window? It should be attached
89  // when shown and during any fades, but should be detached when hidden.
90  bool is_attached() { return [window_ parentWindow] != nil; }
91
92  // Begins fading the status bubble window in or out depending on the value
93  // of |show|.  This must be called from the appropriate fade state,
94  // kBubbleShowingFadeIn or kBubbleHidingFadeOut, or from the appropriate
95  // fully-shown/hidden state, kBubbleShown or kBubbleHidden.  This may be
96  // called at any point during a fade-in or fade-out; it is even possible to
97  // reverse a transition before it has completed.
98  void Fade(bool show);
99
100  // One-shot timer operations to manage the delays associated with the
101  // kBubbleShowingTimer and kBubbleHidingTimer states.  StartTimer and
102  // TimerFired must be called from one of these states.  StartTimer may be
103  // called while the timer is still running; in that case, the timer will be
104  // reset. CancelTimer may be called from any state.
105  void StartTimer(int64 time_ms);
106  void CancelTimer();
107  void TimerFired();
108
109  // Begin the process of showing or hiding the status bubble.  These may be
110  // called from any state, and will take the appropriate action to initiate
111  // any state changes that may be needed.
112  void StartShowing();
113  void StartHiding();
114
115  // Cancel the expansion timer.
116  void CancelExpandTimer();
117
118  // Sets the frame of the status bubble window to |window_frame|, adjusting
119  // for the given mouse position if necessary. Protected for use in tests.
120  void SetFrameAvoidingMouse(NSRect window_frame, const gfx::Point& mouse_pos);
121
122  // The timer factory used for show and hide delay timers.
123  base::WeakPtrFactory<StatusBubbleMac> timer_factory_;
124
125  // The timer factory used for the expansion delay timer.
126  base::WeakPtrFactory<StatusBubbleMac> expand_timer_factory_;
127
128  // Calculate the appropriate frame for the status bubble window. If
129  // |expanded_width|, use entire width of parent frame.
130  NSRect CalculateWindowFrame(bool expanded_width);
131
132  // Returns the flags to be used to round the corners of the status bubble.
133  // Before 10.7, windows have square bottom corners, but in 10.7, the bottom
134  // corners are rounded. This method considers the bubble's placement (as
135  // proposed in window_frame) relative to its parent window in determining
136  // which flags to return. This function may choose to round any corner,
137  // including top corners. Note that there may be other reasons that a
138  // status bubble's corner may be rounded in addition to those dependent on
139  // OS version, and flags will be set or unset elsewhere to address these
140  // concerns.
141  unsigned long OSDependentCornerFlags(NSRect window_frame);
142
143  // The window we attach ourselves to.
144  NSWindow* parent_;  // WEAK
145
146  // The object that we query about our vertical offset for positioning.
147  id delegate_;  // WEAK
148
149  // The window we own.
150  NSWindow* window_;
151
152  // The status text we want to display when there are no URLs to display.
153  NSString* status_text_;
154
155  // The url we want to display when there is no status text to display.
156  NSString* url_text_;
157
158  // The status bubble's current state.  Do not write to this field directly;
159  // use SetState().
160  StatusBubbleState state_;
161
162  // True if operations are to be performed immediately rather than waiting
163  // for delays and transitions.  Normally false, this should only be set to
164  // true for testing.
165  bool immediate_;
166
167  // True if the status bubble has been expanded. If the bubble is in the
168  // expanded state and encounters a new URL, change size immediately,
169  // with no hover delay.
170  bool is_expanded_;
171
172  // The original, non-elided URL.
173  GURL url_;
174
175  // Needs to be passed to ElideURL if the original URL string is wider than
176  // the standard bubble width.
177  std::string languages_;
178
179  DISALLOW_COPY_AND_ASSIGN(StatusBubbleMac);
180};
181
182// Delegate interface
183@interface NSObject(StatusBubbleDelegate)
184// Called to query the delegate about the frame StatusBubble should position
185// itself in. Frame is returned in the parent window coordinates.
186- (NSRect)statusBubbleBaseFrame;
187
188// Called from SetState to notify the delegate of state changes.
189- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
190@end
191
192#endif  // CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
193