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