[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / bookmarks / bookmark_bar_folder_hover_state.mm
blobc8972c4dde4bc1ecd22b99fe60737cb2bb697ac5
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.
5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_hover_state.h"
6 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
8 @interface BookmarkBarFolderHoverState(Private)
9 - (void)setHoverState:(HoverState)state;
10 - (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button;
11 - (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button;
12 @end
14 @implementation BookmarkBarFolderHoverState
16 - (id)init {
17   if ((self = [super init])) {
18     hoverState_ = kHoverStateClosed;
19   }
20   return self;
23 - (NSDragOperation)draggingEnteredButton:(BookmarkButton*)button {
24   if ([button isFolder]) {
25     if (hoverButton_ == button) {
26       // CASE A: hoverButton_ == button implies we've dragged over
27       // the same folder so no need to open or close anything new.
28     } else if (hoverButton_ &&
29                hoverButton_ != button) {
30       // CASE B: we have a hoverButton_ but it is different from the new button.
31       // This implies we've dragged over a new folder, so we'll close the old
32       // and open the new.
33       // Note that we only schedule the open or close if we have no other tasks
34       // currently pending.
36       // Since the new bookmark folder is not opened until the previous is
37       // closed, the NSDraggingDestination must provide continuous callbacks,
38       // even if the cursor isn't moving.
39       if (hoverState_ == kHoverStateOpen) {
40         // Close the old.
41         [self scheduleCloseBookmarkFolderOnHoverButton];
42       } else if (hoverState_ == kHoverStateClosed) {
43         // Open the new.
44         [self scheduleOpenBookmarkFolderOnHoverButton:button];
45       }
46     } else if (!hoverButton_) {
47       // CASE C: we don't have a current hoverButton_ but we have dragged onto
48       // a new folder so we open the new one.
49       [self scheduleOpenBookmarkFolderOnHoverButton:button];
50     }
51   } else if (!button) {
52     if (hoverButton_) {
53       // CASE D: We have a hoverButton_ but we've moved onto an area that
54       // requires no hover.  We close the hoverButton_ in this case.  This
55       // means cancelling if the open is pending (i.e. |kHoverStateOpening|)
56       // or closing if we don't alrealy have once in progress.
58       // Intiate close only if we have not already done so.
59       if (hoverState_ == kHoverStateOpening) {
60         // Cancel the pending open.
61         [self cancelPendingOpenBookmarkFolderOnHoverButton];
62       } else if (hoverState_ != kHoverStateClosing) {
63         // Schedule the close.
64         [self scheduleCloseBookmarkFolderOnHoverButton];
65       }
66     } else {
67       // CASE E: We have neither a hoverButton_ nor a new button that requires
68       // a hover.  In this case we do nothing.
69     }
70   }
72   return NSDragOperationMove;
75 - (void)draggingExited {
76   if (hoverButton_) {
77     if (hoverState_ == kHoverStateOpening) {
78       [self cancelPendingOpenBookmarkFolderOnHoverButton];
79     } else if (hoverState_ == kHoverStateClosing) {
80       [self cancelPendingCloseBookmarkFolderOnHoverButton];
81     }
82   }
85 // Schedule close of hover button.  Transition to kHoverStateClosing state.
86 - (void)scheduleCloseBookmarkFolderOnHoverButton {
87   DCHECK(hoverButton_);
88   [self setHoverState:kHoverStateClosing];
89   [self performSelector:@selector(closeBookmarkFolderOnHoverButton:)
90              withObject:hoverButton_
91              afterDelay:bookmarks::kDragHoverCloseDelay
92                 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
95 // Cancel pending hover close.  Transition to kHoverStateOpen state.
96 - (void)cancelPendingCloseBookmarkFolderOnHoverButton {
97   [self setHoverState:kHoverStateOpen];
98   [NSObject
99       cancelPreviousPerformRequestsWithTarget:self
100       selector:@selector(closeBookmarkFolderOnHoverButton:)
101       object:hoverButton_];
104 // Schedule open of hover button.  Transition to kHoverStateOpening state.
105 - (void)scheduleOpenBookmarkFolderOnHoverButton:(BookmarkButton*)button {
106   DCHECK(button);
107   hoverButton_.reset([button retain]);
108   [self setHoverState:kHoverStateOpening];
109   [self performSelector:@selector(openBookmarkFolderOnHoverButton:)
110              withObject:hoverButton_
111              afterDelay:bookmarks::kDragHoverOpenDelay
112                 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
115 // Cancel pending hover open.  Transition to kHoverStateClosed state.
116 - (void)cancelPendingOpenBookmarkFolderOnHoverButton {
117   [self setHoverState:kHoverStateClosed];
118   [NSObject
119       cancelPreviousPerformRequestsWithTarget:self
120       selector:@selector(openBookmarkFolderOnHoverButton:)
121       object:hoverButton_];
122   hoverButton_.reset();
125 // Hover button accessor.  For testing only.
126 - (BookmarkButton*)hoverButton {
127   return hoverButton_;
130 // Hover state accessor.  For testing only.
131 - (HoverState)hoverState {
132   return hoverState_;
135 // This method encodes the rules of our |hoverButton_| state machine.  Only
136 // specific state transitions are allowable (encoded in the DCHECK).
137 // Note that there is no state for simultaneously opening and closing.  A
138 // pending open must complete before scheduling a close, and vice versa.  And
139 // it is not possible to make a transition directly from open to closed, and
140 // vice versa.
141 - (void)setHoverState:(HoverState)state {
142   DCHECK(
143     (hoverState_ == kHoverStateClosed && state == kHoverStateOpening) ||
144     (hoverState_ == kHoverStateOpening && state == kHoverStateClosed) ||
145     (hoverState_ == kHoverStateOpening && state == kHoverStateOpen) ||
146     (hoverState_ == kHoverStateOpen && state == kHoverStateClosing) ||
147     (hoverState_ == kHoverStateClosing && state == kHoverStateOpen) ||
148     (hoverState_ == kHoverStateClosing && state == kHoverStateClosed)
149   ) << "bad transition: old = " << hoverState_ << " new = " << state;
151   hoverState_ = state;
154 // Called after a delay to close a previously hover-opened folder.
155 // Note: this method is not meant to be invoked directly, only through
156 // a delayed call to |scheduleCloseBookmarkFolderOnHoverButton:|.
157 - (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button {
158   [NSObject
159       cancelPreviousPerformRequestsWithTarget:self
160       selector:@selector(closeBookmarkFolderOnHoverButton:)
161       object:hoverButton_];
162   [self setHoverState:kHoverStateClosed];
163   [[button target] closeBookmarkFolder:button];
164   hoverButton_.reset();
167 // Called after a delay to open a new hover folder.
168 // Note: this method is not meant to be invoked directly, only through
169 // a delayed call to |scheduleOpenBookmarkFolderOnHoverButton:|.
170 - (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button {
171   [self setHoverState:kHoverStateOpen];
172   [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
173       withObject:button];
176 @end