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