Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

bookmark_bar_folder_hover_state.mm

// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/cocoa/bookmark_bar_folder_hover_state.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h" // namespace bookmarks

@interface BookmarkBarFolderHoverState(Private)
- (void)setHoverState:(HoverState)state;
- (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button;
- (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button;
@end

@implementation BookmarkBarFolderHoverState

- (id)init {
  if ((self = [super init])) {
    hoverState_ = kHoverStateClosed;
  }
  return self;
}

- (NSDragOperation)draggingEnteredButton:(BookmarkButton*)button {
  if ([button isFolder]) {
    if (hoverButton_ == button) {
      // CASE A: hoverButton_ == button implies we've dragged over
      // the same folder so no need to open or close anything new.
    } else if (hoverButton_ &&
               hoverButton_ != button) {
      // CASE B: we have a hoverButton_ but it is different from the new button.
      // This implies we've dragged over a new folder, so we'll close the old
      // and open the new.
      // Note that we only schedule the open or close if we have no other tasks
      // currently pending.

      if (hoverState_ == kHoverStateOpen) {
        // Close the old.
        [self scheduleCloseBookmarkFolderOnHoverButton];
      } else if (hoverState_ == kHoverStateClosed) {
        // Open the new.
        [self scheduleOpenBookmarkFolderOnHoverButton:button];
      }
    } else if (!hoverButton_) {
      // CASE C: we don't have a current hoverButton_ but we have dragged onto
      // a new folder so we open the new one.
      [self scheduleOpenBookmarkFolderOnHoverButton:button];
    }
  } else if (!button) {
    if (hoverButton_) {
      // CASE D: We have a hoverButton_ but we've moved onto an area that
      // requires no hover.  We close the hoverButton_ in this case.  This
      // means cancelling if the open is pending (i.e. |kHoverStateOpening|)
      // or closing if we don't alrealy have once in progress.

      // Intiate close only if we have not already done so.
      if (hoverState_ == kHoverStateOpening) {
        // Cancel the pending open.
        [self cancelPendingOpenBookmarkFolderOnHoverButton];
      } else if (hoverState_ != kHoverStateClosing) {
        // Schedule the close.
        [self scheduleCloseBookmarkFolderOnHoverButton];
      }
    } else {
      // CASE E: We have neither a hoverButton_ nor a new button that requires
      // a hover.  In this case we do nothing.
    }
  }

  return NSDragOperationMove;
}

- (void)draggingExited {
  if (hoverButton_) {
    if (hoverState_ == kHoverStateOpening) {
      [self cancelPendingOpenBookmarkFolderOnHoverButton];
    } else if (hoverState_ == kHoverStateClosing) {
      [self cancelPendingCloseBookmarkFolderOnHoverButton];
    }
  }
}

// Schedule close of hover button.  Transition to kHoverStateClosing state.
- (void)scheduleCloseBookmarkFolderOnHoverButton {
  DCHECK(hoverButton_);
  [self setHoverState:kHoverStateClosing];
  [self performSelector:@selector(closeBookmarkFolderOnHoverButton:)
             withObject:hoverButton_
             afterDelay:bookmarks::kDragHoverCloseDelay];
}

// Cancel pending hover close.  Transition to kHoverStateOpen state.
- (void)cancelPendingCloseBookmarkFolderOnHoverButton {
  [self setHoverState:kHoverStateOpen];
  [NSObject
      cancelPreviousPerformRequestsWithTarget:self
      selector:@selector(closeBookmarkFolderOnHoverButton:)
      object:hoverButton_];
}

// Schedule open of hover button.  Transition to kHoverStateOpening state.
- (void)scheduleOpenBookmarkFolderOnHoverButton:(BookmarkButton*)button {
  DCHECK(button);
  hoverButton_.reset([button retain]);
  [self setHoverState:kHoverStateOpening];
  [self performSelector:@selector(openBookmarkFolderOnHoverButton:)
             withObject:hoverButton_
             afterDelay:bookmarks::kDragHoverOpenDelay];
}

// Cancel pending hover open.  Transition to kHoverStateClosed state.
- (void)cancelPendingOpenBookmarkFolderOnHoverButton {
  [self setHoverState:kHoverStateClosed];
  [NSObject
      cancelPreviousPerformRequestsWithTarget:self
      selector:@selector(openBookmarkFolderOnHoverButton:)
      object:hoverButton_];
  hoverButton_.reset();
}

// Hover button accessor.  For testing only.
- (BookmarkButton*)hoverButton {
  return hoverButton_;
}

// Hover state accessor.  For testing only.
- (HoverState)hoverState {
  return hoverState_;
}

// This method encodes the rules of our |hoverButton_| state machine.  Only
// specific state transitions are allowable (encoded in the DCHECK).
// Note that there is no state for simultaneously opening and closing.  A
// pending open must complete before scheduling a close, and vice versa.  And
// it is not possible to make a transition directly from open to closed, and
// vice versa.
- (void)setHoverState:(HoverState)state {
  DCHECK(
    (hoverState_ == kHoverStateClosed && state == kHoverStateOpening) ||
    (hoverState_ == kHoverStateOpening && state == kHoverStateClosed) ||
    (hoverState_ == kHoverStateOpening && state == kHoverStateOpen) ||
    (hoverState_ == kHoverStateOpen && state == kHoverStateClosing) ||
    (hoverState_ == kHoverStateClosing && state == kHoverStateOpen) ||
    (hoverState_ == kHoverStateClosing && state == kHoverStateClosed)
  ) << "bad transition: old = " << hoverState_ << " new = " << state;

  hoverState_ = state;
}

// Called after a delay to close a previously hover-opened folder.
// Note: this method is not meant to be invoked directly, only through
// a delayed call to |scheduleCloseBookmarkFolderOnHoverButton:|.
- (void)closeBookmarkFolderOnHoverButton:(BookmarkButton*)button {
  [NSObject
      cancelPreviousPerformRequestsWithTarget:self
      selector:@selector(closeBookmarkFolderOnHoverButton:)
      object:hoverButton_];
  [self setHoverState:kHoverStateClosed];
  [[button target] closeBookmarkFolder:button];
  hoverButton_.reset();
}

// Called after a delay to open a new hover folder.
// Note: this method is not meant to be invoked directly, only through
// a delayed call to |scheduleOpenBookmarkFolderOnHoverButton:|.
- (void)openBookmarkFolderOnHoverButton:(BookmarkButton*)button {
  [self setHoverState:kHoverStateOpen];
  [[button target] performSelector:@selector(openBookmarkFolderFromButton:)
      withObject:button];
}

@end

Generated by  Doxygen 1.6.0   Back to index